LeetCode 每日一题笔记
0. 前言
- 日期:2026.05.22
- 题目:33. 搜索旋转排序数组
- 难度:中等
- 标签:数组、二分查找
1. 题目理解
问题描述 :
给定一个升序数组,在未知下标 k 处左旋后,得到数组 nums(所有值互不相同)。给定目标值 target,返回它在数组中的下标,不存在则返回 -1。要求时间复杂度为 O(logn)O(\log n)O(logn)。
示例:
输入:
nums = [4,5,6,7,0,1,2],target = 0输出:
4解释:目标值
0位于下标4。
输入:nums = [4,5,6,7,0,1,2],target = 3输出:
-1解释:目标值不存在于数组中。
2. 解题思路
核心观察
- 旋转后的数组仍保持局部有序 :被
mid分成的两个区间中,必有一个是完全有序的; - 利用二分查找,先判断
mid所在的区间是否有序,再根据target与有序区间的边界关系,决定下一步的搜索方向。
算法步骤
- 初始化左右指针
left = 0,right = nums.length - 1; - 循环直到
left > right:- 计算
mid = left + (right - left) / 2; - 若
nums[mid] == target,直接返回mid; - 判断左半区是否有序(
nums[mid] >= nums[left]):- 若
target在左半区范围内,收缩右边界; - 否则收缩左边界;
- 若
- 若右半区有序:
- 若
target在右半区范围内,收缩左边界; - 否则收缩右边界;
- 若
- 计算
- 循环结束未找到,返回
-1。
3. 代码实现
java
package lc33;
public class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
}
// 左半区有序
if (nums[mid] >= nums[left]) {
if (target >= nums[left] && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
// 右半区有序
else {
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
return -1;
}
}
4. 代码优化说明
减少冗余判断,通过逻辑等价简化分支,保持可读性的同时压缩代码:
java
package lc33;
public class Solution {
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) return mid;
if (nums[mid] >= nums[left]) {
left = (target >= nums[left] && target < nums[mid]) ? left : mid + 1;
right = (target >= nums[left] && target < nums[mid]) ? mid - 1 : right;
} else {
left = (target > nums[mid] && target <= nums[right]) ? mid + 1 : left;
right = (target > nums[mid] && target <= nums[right]) ? right : mid - 1;
}
}
return -1;
}
}
5. 复杂度分析
-
时间复杂度 :O(logn)O(\log n)O(logn)
二分查找每次将区间减半,最坏情况下执行 log2n\log_2 nlog2n 次循环。
-
空间复杂度 :O(1)O(1)O(1)
仅使用常数级额外变量,无递归栈或额外数组开销。
6. 总结
- 核心思路:局部有序的二分查找,利用旋转数组的特性,每次只在有序区间内判断目标值位置;
- 关键技巧:通过
nums[mid]与nums[left]的大小关系,快速判断哪一侧区间有序; - 优化后代码通过三目运算符简化分支,逻辑更紧凑,同时保持原算法的正确性与时间复杂度。