力扣-Hot100-二分篇

114 阅读2分钟

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

寻找最左边和最右边元素的板子题

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        ans = [-1, -1]
        n = len(nums)
        if n == 0:
            return ans
        nums.sort()
        l, r = 0, n - 1
        while l < r:
            mid = l + r >> 1
            if target <= nums[mid]:
                r = mid
            else:
                l = mid + 1
        if nums[r] == target:
            ans[0] = r
        l, r = 0, n - 1
        while l < r:
            mid = (l + r + 1) // 2
            if target >= nums[mid]:
                l = mid
            else:
                r = mid - 1
        if nums[r] == target:
            ans[1] = r
        return ans
        

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

数组有序并且所有的元素没有重复,数组发生旋转,可以通过nums[0]或者nums[-1]将数组分为两部分,所以我们可以以nums[0]或者nums[-1]为基准,进行二分搜索。

class Solution:
    def findMin(self, nums: List[int]) -> int:
        n = len(nums)
        i, j = 0, n - 1
        # while i < j:
        #     mid = i + j + 1 >> 1
        #     if nums[mid] >= nums[0]:
        #         i = mid
        #     else:
        #         j = mid - 1
        # return nums[(j + 1) % n]
        while i < j:
            mid = i + j >> 1
            if nums[mid] <= nums[-1]:
                j = mid
            else:
                i = mid + 1
        return nums[j]

33. 搜索旋转排序数组

思路:二分解法,首先确定旋转的位置,然后根据位置与target的大小,判断是搜索左边还是搜索右边。

  1. 确定旋转位置,题目中数据不重复,且从小到大排序,如果发生旋转,那就会变成升-降-升的这种排序方式,如果以nums[0]为基准,若nums[i]大于target,可以继续向右找旋转点,否则需要向左寻找旋转点,可以利用二分进行寻找。

查找方式如下:我这里找的是大于nums[0]的最右边的元素。也可以尝试找小于nums[-1]的最左边的元素。

# 方法1
n = len(nums)
l, r = 0, n - 1
while l < r:
    mid = l + r + 1 >> 1
    if nums[mid] >= nums[0]:
        l = mid
    else:
        r = mid - 1

# 方法2
n = len(nums)
l, r = 0, n - 1
while l < r:
    mid = l + r >> 1
    if nums[mid] <= nums[-1]:
        r = mid
    else:
        l = mid + 1

所有代码如下

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        l, r = 0, n - 1
        while l < r:
            mid = l + r + 1 >> 1
            if nums[mid] >= nums[0]:
                l = mid
            else:
                r = mid - 1
        idx = r
        if target > nums[-1]:
            l, r = 0, idx
        else:
            l, r = (idx + 1) % n, n - 1
        while l < r:
            mid = l + r >> 1
            if nums[mid] >= target:
                r = mid
            else:
                l = mid + 1
        return r if nums[r] == target else -1