33. 搜索旋转排序数组

整数数组 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

题目链接:33. 搜索旋转排序数组 - 力扣(LeetCode) (leetcode-cn.com)

二分搜索

思路:

根据之前写的 leetcode153 的思路,可以先找数组的最小值,也就是将数组分为两个升序数组,判断target在哪个数组,然后再次使用二分法,查找是否有目标数。

  • 首先判断特殊情况,数列中只有一个数字,可以直接判断该数字是否为目标值,若是目标值则返回0,否则返回-1
  • 接着判断是否需要划分为两个数组
    • 若数组的首小于数组的尾则说明这个数组依旧是一个递增数组,不必划分。
    • 否则需要划分数组,找到目标值可能存在的区间
  • 划分数组也是使用二分法
    • 首先初始化设置左右两个指针 left = 0right = len(nums)-1
    • 我们希望最后 left 是指向第一个递增数组的尾部,即left为原数组的最大值right 是指向第二个递增数组的首部,right为原数组的最小值
    • 退出循环时left = right - 1,所以 while循环的条件可以设置为 left < right-1
    • 若目标值小于最小值 target < nums[right],或者说大于最大值 target > nums[left],那么直接返回-1
    • 若目标值大于等于nums[0] ,则表示目标值在左边的递增数组中。否则就在右边的递增数组中。
  • 接着还是一个二分法来在递增数组中寻找目标值
    • 依旧设置左右两个指针 leftright
    • 循环条件left <= right
    • mid 的设置,防止溢出mid = left + (right-left)//2
    • mid指向的值正好等于目标值时,直接返回mid
    • 若小于则说明目标值在右边,left = mid + 1
    • 若大于则说明目标值在左边,right = mid - 1
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        n = len(nums)
        if n == 1:
            if nums[0] == target:
                return 0
            else:
                return -1
        if nums[0] > nums[n-1]:
            left = 0
            right = n-1
            while(left < right-1):
                mid = left + (right-left)//2
                if nums[mid] < nums[right]:
                    right = mid
                elif nums[mid] > nums[right]:
                    left = mid
            if target < nums[right] or target > nums[left]:
                return -1
            if target >= nums[0]:
                right = left
                left = 0
            elif target < nums[0]:
                left = right
                right = n-1
        elif nums[0] < nums[n-1]:
            if target < nums[0] or target > nums[n-1]:
                return -1
            left = 0
            right = n-1
        while (left <= right):
            mid = left + (right-left)//2
            if nums[mid] == target:
                return mid
            elif nums[mid] < target:
                left = mid + 1
            elif nums[mid] > target:
                right = mid - 1
        return -1
posted on 2021-09-21 12:56  墩墩儿er  阅读(85)  评论(0)    收藏  举报