LeetCode Hot100(49/100)——33. 搜索旋转排序数组

文章目录

一、题目描述

给定一个旋转排序数组 nums(升序排序后某个位置被旋转),以及一个目标值 target,请你在数组中寻找该目标值。如果存在,返回它的下标;否则返回 -1

示例:

复制代码
输入:nums = [4,5,6,7,0,1,2], target = 0  
输出:4

二、问题分析

一个「旋转排序数组」其实是一个被分成两个有序子数组的数组,例如:

复制代码
原始升序数组: [0,1,2,3,4,5,6]
旋转后可能变为: [4,5,6,0,1,2,3]

数组依然包含两个有序区间:

  • 左区间:递增
  • 右区间:递增

我们可以用二分查找的思想进行搜索,只需在二分过程中判断当前区间的性质(是否有序),再决定搜索方向。


三、思维导图

Search in Rotated Sorted Array
原理
二分查找
判断有序区间
决定搜索方向
情况分析
左半部分有序
右半部分有序
实现思路
mid 与 left/right 比较
target 范围判断
移动 left 或 right
复杂度
时间 O(log n)
空间 O(1)


四、解法一:标准二分法思路

1. 核心思路 🧠

在每轮二分中:

  1. 计算中点 mid
  2. 判断左半段是否有序;
  3. 如果左半段有序:
    • 判断目标是否在左半段范围内;
    • 若是,则移动右指针;
    • 若否,则移动左指针;
  4. 如果右半段有序:
    • 判断目标是否在右半段范围内;
    • 若是,则移动左指针;
    • 若否,则移动右指针。

2. 流程图









开始
计算 mid = (left + right) / 2
numsmid == target?
返回 mid
numsleft <= numsmid?
target 在左区间?
right = mid - 1
left = mid + 1
target 在右区间?
left = mid + 1
right = mid - 1
继续循环
结束,未找到返回 -1


五、代码实现(Java)

java 复制代码
public class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            
            // 找到目标
            if (nums[mid] == target) return mid;
            
            // 左半部分有序
            if (nums[left] <= nums[mid]) {
                if (nums[left] <= target && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } 
            // 右半部分有序
            else {
                if (nums[mid] < target && target <= nums[right]) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}

六、复杂度分析

类型 分析
时间复杂度 O(log n) --- 因为每次都折半查找
空间复杂度 O(1) --- 仅使用常数级变量

七、解法二:先找旋转点 + 普通二分查找

1. 思路要点

如果我们能先找到旋转点,即最小值所在的位置 ,就能确定左右两段的有序区间。

接着分别在对应的区间使用常规二分查找。

2. 时序图(查找旋转点与搜索过程)

数组 算法 数组 算法 查找旋转点 ->> 最小值位置 判断 target 在左/右区间 根据区间进行二分搜索 返回索引或 -1

3. 实现代码(Java)

java 复制代码
public class Solution {
    public int search(int[] nums, int target) {
        int pivot = findPivot(nums);
        if (nums[pivot] == target) return pivot;
        
        if (target >= nums[0]) {
            return binarySearch(nums, 0, pivot - 1, target);
        } else {
            return binarySearch(nums, pivot, nums.length - 1, target);
        }
    }

    private int findPivot(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) {
            int mid = (left + right) / 2;
            if (nums[mid] > nums[right]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    private int binarySearch(int[] nums, int left, int right, int target) {
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        return -1;
    }
}

八、对比分析

方法 思路 优点 缺点
单次二分法 在一次查找中同时判断有序区间 简洁高效 分支逻辑稍复杂
找旋转点 + 二分 先定位旋转点再两次查找 思路清晰、结构化 要进行两次二分,代码稍长

通过二分的逻辑提升,搜索旋转排序数组可以在 O(log n) 时间内完成。

关键是判断当前哪一部分有序 ,再结合 target 的取值范围决定下一步的查找方向。

这道题是经典的二分查找变形题,非常适合掌握二分技巧与边界判断。

相关推荐
To_OC3 小时前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
用户938515635078 小时前
从 O(n²) 到 O(nlogn):一文读懂快速排序的“快”与“妙”
javascript·算法
To_OC9 小时前
手写快排次次翻车?别死背快排模板了,这才是面试官想听的底层逻辑
javascript·算法·排序算法
饼干哥哥10 小时前
Reddit VOC调研太慢?搭一个AI专家团队半小时洞察任何品类|以猫用饮水机为例
人工智能·算法·ai编程
地平线开发者11 小时前
Transformer模型部署之性能优化指南
算法
地平线开发者11 小时前
人在途中:从“编译失败”到“模型可落地”——CUDA 自定义算子
算法·自动驾驶
半个落月14 小时前
从递归到快速排序:用 JavaScript 把分治思想讲明白
javascript·算法·面试
小月土星15 小时前
JavaScript 快速排序:从 pivot、双指针到分治思想
javascript·算法·面试
小月土星15 小时前
JavaScript 递归入门:从 1 到 n 求和,再到数组扁平化
javascript·算法·面试