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
nums[mid] == target?
返回 mid
nums[left] <= nums[mid]?
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 的取值范围决定下一步的查找方向。

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

相关推荐
熬了夜的程序员2 小时前
【LeetCode】116. 填充每个节点的下一个右侧节点指针
算法·leetcode·职场和发展
郝学胜-神的一滴2 小时前
贝叶斯之美:从公式到朴素贝叶斯算法的实践之旅
人工智能·python·算法·机器学习·scikit-learn
静心观复2 小时前
贝叶斯公式拆解
算法
智者很聪明2 小时前
排序算法—冒泡排序
算法·排序算法
AC赳赳老秦2 小时前
云原生AI趋势:DeepSeek与云3.0架构协同,提升AI部署性能与可移植性
大数据·前端·人工智能·算法·云原生·架构·deepseek
gorgeous(๑>؂<๑)2 小时前
【ICLR26-Oral Paper-Meta】先见之明:揭秘语言预训练中大型语言模型的视觉先验
人工智能·深度学习·算法·机器学习·语言模型
tod1132 小时前
力扣基础算法分类刷题:位运算、数学、数组与字符串详解
算法·leetcode·职场和发展
ValhallaCoder2 小时前
hot100-图论
数据结构·python·算法·图论
熬了夜的程序员2 小时前
【LeetCode】118. 杨辉三角
linux·算法·leetcode