LeetCode33 搜索旋转排序数组

51 阅读2分钟

leetcode.cn/problems/se…

image.png

解法一:二分查找变种

二分搜索算法不仅能应用在排好序的数组,如果这个数组不是一个标准的有序数组,只要稍微修改算法逻辑,也能使用二分搜索。还是那句话,二分思想的核心在于快速收缩搜索区间。

思路分析:把一个排好序的数组就好比一段斜向上的山坡,沿着一个元素旋转数组,相当于将山坡切断并旋转,在原本平滑的山坡上产生一个「断崖」,「断崖」左侧的所有元素比右侧所有元素都大

image.png 可以在这样一个存在断崖的山坡上用二分搜索算法搜索元素的,主要分成两步:

  1. 确定中点mid是落在断崖左侧还是右侧;
  2. 根据 target 和 nums[left], nums[right], nums[mid] 的相对大小收缩搜索区间

image.png

假设nums[mid]刚好等于target,那么直接找到答案。

假设 mid 在「断崖」左侧,那么可以肯定 nums[left..mid] 是连续且有序的,可以在这段范围内执行二分查找,所以如果 nums[left] <= target < nums[mid],则可以收缩右边界(right = mid-1),否则应该收缩左边界(left = mid+1)。

假设 mid 在「断崖」右侧,那么可以肯定 nums[mid..right] 是连续且有序的,可以在这段范围内执行二分查找,所以如果 nums[mid] < target <= nums[right],则可以收缩左边界(left = mid+1),否则应该收缩右边界(right = mid-1)。

func search(nums []int, target int) int {
    left, right := 0, len(nums)-1
    for left <= right{
        mid := left + (right - left)/2
        if nums[mid] == target {
            return mid
        }
        if nums[mid] >= nums[left]{ // nuns[mid]处于左半边,此时 nums[left..mid] 有序
            if target >= nums[left] && target < nums[mid]{
                right = mid - 1
            }else{
                left = mid + 1
            }
        }else { // nuns[mid]处于右半边,此时 nums[mid..right] 有序
            if target <= nums[right] && target > nums[mid]{
                left = mid+1
            }else{
                right = mid-1
            }
        }
    }
    return -1
}