搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值互不相同
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

这里数组中的值互不相同需要注意。

题目分析

由于原数组有序,旋转后,旋转位置的左右两边的序列都是升序,因此,可以使用二分查找。
我们可以判断target和mid以及左右两边界的关系来确定有序区域。

  • 如果mid >= nums[left],则满足下图左边的情况,此时,判断target的位置
  1. 如果 nums[left] <= target < nums[mid],则将范围缩小至[left,mid-1];
  2. 其他情况在[mid+1,right]中寻找;
  • 如果mid < nums[left],则满足下图右边的情况,此时,判断target的位置
  1. 如果 nums[mid] < target <= nums[right],则将范围缩小至[mid+1,right]
  2. 其他情况在[left,mid-1]搜索。
    注意和边界判断时,都需要等号。
    示例示例

代码实现

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        left,right = 0,n-1
        while left <= right:
            mid = (left+right)//2
            if nums[mid] == target:
                return mid
            if nums[mid] >= nums[left]:
                if nums[left] <= target < nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
            else:
                if nums[mid] < target <= nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1
        return -1

搜索旋转排序数组II

本题为上一题的扩展,当数组中存在重复元素时,如何查找target。
此时可能存在重复元素分散在旋转中心两端的情况,例如:[2,2,2,2,6,0,1,2]。此时,可能出现nums[left] = nums[mid] = nums[right]的情况,导致无法判断哪个区间是有序的。
因此,对于这种情况,我们需要将二分区间进行压缩。

代码实现

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if n == 1:
            return nums[0] == target
        left,right = 0,n-1
        while left <= right:
            mid = (left+right)//2
            if nums[mid] == target:
                return True
            if nums[left] == nums[mid] and nums[right] == nums[mid]:
                left += 1
                right -= 1
            elif nums[mid] >= nums[left]:
                if nums[left] <= target < nums[mid]:
                    right = mid - 1
                else:
                    left = mid + 1
            else:
                if nums[mid] < target <= nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1
        return False