🔍 题目解析
给定一个 旋转排序数组 nums,该数组是一个 递增有序数组 在某个未知的索引处 旋转 形成的。例如:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
目标:在 O(log n) 时间复杂度 内找到 target 的索引,找不到返回 -1。
📝 详细思路
这道题的本质是 二分查找,但由于数组发生了旋转,我们需要额外判断 mid 位置属于 左半部分 还是 右半部分,从而确定 target 可能在哪一侧。
💡 关键点
1. 常规二分查找
• 计算 mid = left + (right - left) / 2
• nums[mid] == target 时,返回 mid
2. 判断 mid 属于左半部分还是右半部分
• 若 nums[mid] >= nums[0],说明 mid 在左半部分
• 若 nums[mid] < nums[0],说明 mid 在右半部分
3. 基于 target 位置进行调整
• mid 在左半部分
• 若 target 在 左半部分 且 target < nums[mid],搜索左侧 right = mid - 1
• 否则,搜索右侧 left = mid + 1
• mid 在右半部分
• 若 target 在 右半部分 且 target > nums[mid],搜索右侧 left = mid + 1
• 否则,搜索左侧 right = mid - 1
📌 代码运行步骤
示例 1
输入: nums = [4,5,6,7,0,1,2], target = 0
初始状态
left | right | mid | nums[mid] | target |
---|---|---|---|---|
0 | 6 | 3 | 7 | 0 |
1️⃣ 第一次循环
• mid = (0 + 6) / 2 = 3
• nums[mid] = 7
• nums[mid] >= nums[0],mid 在 左半部分
• target = 0 在 右半部分
• left = mid + 1 = 4
left | right | mid | nums[mid] | target |
---|---|---|---|---|
4 | 6 | 5 | 1 | 0 |
2️⃣ 第二次循环
• mid = (4 + 6) / 2 = 5
• nums[mid] = 1
• nums[mid] < nums[0],mid 在 右半部分
• target = 0 在 右半部分 且 target < nums[mid]
• right = mid - 1 = 4
left | right | mid | nums[mid] | target |
---|---|---|---|---|
4 | 4 | 4 | 0 | 0 |
3️⃣ 第三次循环
• mid = (4 + 4) / 2 = 4
• nums[mid] == target
• 返回 mid = 4
示例 2
输入: nums = [4,5,6,7,8,1,2,3], target = 8
初始状态
left | right | mid | nums[mid] | target |
---|---|---|---|---|
0 | 7 | 3 | 7 | 8 |
1️⃣ 第一次循环
• mid = (0 + 7) / 2 = 3
• nums[mid] = 7
• nums[mid] >= nums[0],mid 在 左半部分
• target = 8 也在 左半部分,且 target > nums[mid]
• left = mid + 1 = 4
left | right | mid | nums[mid] | target |
---|---|---|---|---|
4 | 7 | 5 | 1 | 8 |
2️⃣ 第二次循环
• mid = (4 + 7) / 2 = 5
• nums[mid] = 1
• nums[mid] < nums[0],mid 在 右半部分
• target = 8 在 左半部分
• right = mid - 1 = 4
left | right | mid | nums[mid] | target |
---|---|---|---|---|
4 | 4 | 4 | 8 | 8 |
3️⃣ 第三次循环
• mid = (4 + 4) / 2 = 4
• nums[mid] == target
• 返回 mid = 4
🛠 代码优化
class Solution {
public:int search(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] == target) return mid;// mid 在左半部分if (nums[mid] >= nums[0]) {if (target >= nums[0] && target < nums[mid]) {right = mid - 1;} else {left = mid + 1;}} // mid 在右半部分else {if (target < nums[0] && target > nums[mid]) {left = mid + 1;} else {right = mid - 1;}}}return -1;}
};
🎯 复杂度分析
时间复杂度 | 空间复杂度 |
---|---|
O(log n) | O(1) |
• 时间复杂度:二分查找,每次搜索范围缩小一半,故为 O(log n)
• 空间复杂度:只使用了常数级别变量,故为 O(1)