经典算法之二分查找

  1. 寻找旋转排序数组中的最小值 II

元素可能重复

class Solution:
    def findMin(self, nums: List[int]) -> int:
        left = 0
        right = len(nums) - 1
        while left < right:
            if nums[left] < nums[right]:
                return nums[left]
            mid = (left + right) // 2
            if nums[mid] == nums[right]:
                # 这里是精髓,和二分查找不一样。另外mid和右边界比,也和二分查找不一样。
                # 二分查找是直接和目标元素比
                right -= 1
            elif nums[mid] < nums[right]:
                right = mid
            else:
                left = mid + 1
        return nums[left]

二分查找,无重复元素,求lower_bound。
对应leetcode 35. 搜索插入位置

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)

        while left < right:
            mid = left + (right - left)//2
            if nums[mid] == target:
                return mid
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return left

说明:

  1. 算法使用了左闭右开区间。初始条件一定是[0, len(nums))。相应条件为left < right
  2. 注意和二分查找区别,nums[right] > target时。
    right = mid而不是mid-1。
  3. 注意避免死循环。当mid == right时,必有left = might。这时就退出循环。

有重复元素时求下界和上界

对应leetcode 34. 在排序数组中查找元素的第一个和最后一个位置

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        lower_index = self.lower_bound(nums, 0, len(nums), target)
        if lower_index == len(nums) or nums[lower_index] != target:
            return [-1, -1]
        upper_index = self.upper_bound(nums, lower_index + 1, len(nums), target)
        return [lower_index, upper_index - 1]

    def lower_bound(self, nums, left, right, target):
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid
        return left
    
    def upper_bound(self, nums, left, right, target):
        while left < right:
            mid = left + (right - left) // 2
            if nums[mid] <= target:
                left = mid + 1
            else:
                right = mid
        return left

说明:求下界和上界时,基本结构一致。区别仅在于相等时的处理。
1. 求下界,nums[mid] = target时,往左搜索。令right = mid
2. 求上界,nums[mid] = target时,往右搜索。 left = mid + 1

可以看出针对左开右闭区别,往右搜索一定是left = mid + 1.而往左搜索是right = mid。这里有着细微的差别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值