代码随想录算法训练营Day1 | 704. 二分查找,27. 移除元素,977. 有序数组的平方

目录

704. 二分查找

27. 移除元素

977. 有序数组的平方


704. 二分查找

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:循环的条件,即while里写什么

        二分查找前提:①有序数组;②无重复元素。

        双指针法:左右指针向数组中心移动,直到找到目标元素。 

        解题卡点:当循环到最后时,左右指针指向相同的元素索引,此时左右指针索引相同。即当右指针小于左指针时跳出循环。

        Tips:求中间索引时,为防止(a+b)/2的分子溢出,使用a+(b-a)/2替代。也可使用a+((b-a)>>1)替代。对于二进制的正数来说,右移x位相当于除以2的x次方。

        总结:二分查找难点在于如何循环,控制边界条件。这里我将左右指针代表为元素的索引,求出的mid也为索引,nums[索引]一定可以取到。当nums[mid]≠target时,mid索引对应的元素已经判断过,故指针移动时不用把mid再包含进去。当指针移动到最后,right=left时,因为是索引所以nums[mid]依然可以取到,代表着right与left指向同一个元素,只有当right<left时才无法继续,故循环条件为right≥left。

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)-1
        while right >= left: # 当两者相等时,索引依然有效
            mid = left+(right-left)//2 # 防加法溢出
            if nums[mid] > target:
                right = mid-1 # mid索引对应的元素被上一行判断了,right应该比mid再小一位
            elif nums[mid] < target:
                left = mid+1 # left应该比mid再大一位
            else:
                return mid
        return -1 # 跳出循环时代表目标值不在数组中,返回-1

    # 时间复杂度 O(log n)
    # 空间复杂度 O(1)

27. 移除元素

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:①有连续的要被移除的元素时,如何写;②快指针指到了数组末尾该被移除的元素后,指针索引+1,超出了数组边界

        双指针法:快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组;慢指针:指向更新新数组下标的位置。

        解题卡点:

        ①有连续目标元素时,一开始写成了下方的while形式,结果到数组末尾索引超出边界了。因此只用1个外层while,内层进行if判断,若满足条件指针+1,回到外层进行循环,若再满足条件再指针+1,回到外层进行循环。此时慢指针不动,而快指针+2,实现用if代替内层while;

while fast <= len(nums)-1:
    while nums[fast] == val:
        fast += 1
    nums[slow] = nums[fast]
    slow += 1
    fast += 1

    # 错误

        ②如上gif图,快指针指到数组最后一个元素,且该元素需被删除时,索引+1。但快指针指向的元素会被赋值给慢指针,此时nums[slow]=nums[fast]=num[len(nums)],超出索引边界。因此当快指针指到最后一个元素时应停下来。故若元素满足条件,回到while进行判断,若为最后一个元素跳出循环。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slow = 0 # 慢指针
        fast = 0 # 快指针
        while fast <= len(nums)-1: # 指针代表索引,最大索引为len(nums)-1,若fast再大跳出循环
            if nums[fast] == val:
                fast += 1
                continue # 快指针指向目标元素后,回到while循环,防止fast超出索引使下一行报错
            nums[slow] = nums[fast]
            slow += 1
            fast += 1
        return slow

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)

        总结:原地移除元素,使用双指针法进行。当快指针指向目标元素时,慢指针不动,快指针+1,同时将快指针指向的除目标元素之外的值赋给慢指针的值。当快指针指向最后一个元素,且慢指针的索引代表着前k个元素的个数。

        另一种写法,使用不等于进行if判断,更方便。另外,对nums[fast]和val使用等于和不等于判断的写法不同,需注意。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slow = 0
        fast = 0
        while fast <= len(nums)-1:
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)

977. 有序数组的平方

题目链接:. - 力扣(LeetCode)

文章讲解:代码随想录

解题卡点:无

        双指针法:左右指针指向数组第一个元素和最后一个元素,判断元素平方后大小,倒着填入空白数组,随后指针向数组中心移动。 

        总结:数组以非递减顺序排序,平方后最大的元素分布在数组两端。左右指针指向数组第一个元素和最后一个元素,判断平方大小后,将最大的值倒着填入空白数组,随后指针向数组中心移动。

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        res = [0]*len(nums) # 空白数组,用于存放结果
        idx = len(nums)-1 # 空白数组的索引,将结果倒着填入空白数组
        left = 0 # 左指针
        right = len(nums)-1 # 右指针
        while right >= left: # 循环到最后时左右指针指向相同元素,此时right==left
            if nums[right]**2 >= nums[left]**2:
                res[idx] = nums[right]**2
                right -= 1 # 右指针向数组中心移动
            else:
                res[idx] = nums[left]**2
                left += 1 # 左指针向数组中心移动
            idx -= 1
        return res

    # 时间复杂度 O(n)
    # 空间复杂度 O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值