Day01 数组理论基础 | 704. 二分查找,27. 移除元素

LeetCode 704 二分查找

题目描述

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

输入:nums = [-1,0,3,5,9,12],target = 9
输出: 4
解释: 9 出现在nums中并且下标为 4

注意点

  • 有序数组
  • 无重复元素
  • 注意左右开闭区间,避免重复遍历或遗漏右区间元素

方法一:左闭右闭区间 [left, right]

def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        #method 1
        left = 0
        right = len(nums) - 1
        while left <= right:
            # mid = (left + right) // 2
            mid = left + (right-left) // 2 #难点
            print(left, mid, right)
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return -1

方法二:左闭右开区间 [left, right)

def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        #method 2
        left = 0
        right = len(nums)
        while left < right:
            # mid = (left + right) // 2
            mid = left + (right-left) // 2 #难点
            print(left, mid, right)
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return -1

难点

关于mid的计算,最开始直接用的 mid = (left + right) // 2 ,可能测试用例比较少没有遇到报错,侥幸通过。后来看了别人的分析后才反应过来。(附上原解析)

关于mid的写法:作者:FancyIcookie

  • 这个问题我思考很久,mid = (right - left) // 2mid = (right + left) // 2 以及 mid = left + (right - left) // 2
    • mid = (right - left) // 2 这种写法运用在这里根本就是错误的。因为right - left 仅仅代表两者之间相差几个数的距离,再除以2只是说从左到右的一半距离,和下标就没有关系了。

    • mid = (right + left) // 2这种写法会发生上溢问题。int 占用 4 字节,32 比特,数据范围为:2147483648 ~ 2147483647 [-2^31 ~ 2^31-1]

      那么对于两个都接近 2147483647的数字而言,它们相加的结果将会溢出,变成负数。所以,为了避免溢出情况的发生,我们不采用这种写法。

    • mid = left + (right - left) // 2 从左指针到右指针的一半距离 + 左指针的下标 才是符合题的下标位置。


LeetCode 27 移除元素

题目描述:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度2, 并且nums中的前两个元素均为2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而nums = [2,2,3,3] 或nums = [2,2,0,0],也会被视作正确答案。

方法一:暴力法

def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        length = len(nums)
        count = 0
        for i in range(length): 
            print(i)
            if nums[i] == val:
                nums[i] = 51 #原题限定num[i] <= 50
                count += 1
            print(nums)
            print(count)
        nums.sort()
        return length - count

方法二:双指针法

def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        slow, fast = 0, 0
        length = len(nums)
        for fast in range(length):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
        return slow

fast::在前面遍历数组元素

slow:在后面更新数组元素

值等于target的元素不会被更新到新数组下表slow里,因此新数组前slow个元素为移除目标元素后的目标数组。

总结

  • 二分法看一遍基本理解,需要注意左右区间的开闭,以及mid的计算
  • 双指针法属于新学的一种,感觉这种快慢指针思想可以运用到很多地方,但是容易忘记,需要时不时看题解复习
  • 第一次写博客,敬请多多指教~

代码随想录讲解原文链接:

  1. 二分查找
  2. 移除元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值