【LeetCode】33. 搜索旋转排序数组
解题思路
该问题要求在 旋转后的有序数组 中查找目标值,且时间复杂度需为 O(log n)。核心思路是 二分查找的变体,利用旋转数组的特性:数组被分为两个有序子数组,通过判断有序区间调整搜索范围。
关键步骤:
- 确定有序区间:每次计算中间点
mid,比较nums[left]和nums[mid]的值,判断左半部分是否有序。- 若左半部分有序 (
nums[left] <= nums[mid]),检查目标值是否在左半部分的范围内。 - 若右半部分有序 (
nums[left] > nums[mid]),检查目标值是否在右半部分的范围内。
- 若左半部分有序 (
- 调整搜索范围:根据目标值与有序区间的关系,移动左右指针缩小搜索范围。
- 终止条件:找到目标值或左右指针交叉(未找到)。
代码实现
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[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 }
代码注释
- 循环条件:
left <= right确保搜索区间有效。 - 中间点计算:
mid := left + (right-left)/2避免整数溢出。 - 有序区间判断:
- 若
nums[left] <= nums[mid],左半部分有序。 - 否则右半部分有序。
- 若
- 范围调整:根据目标值与有序区间的关系,移动指针。
复杂度分析
- 时间复杂度:O(log n),每次二分将搜索范围减半。
- 空间复杂度:O(1),仅使用常数级变量。
运行示例
func main() { fmt.Println(search([]int{4,5,6,7,0,1,2}, 0)) // 输出 4 fmt.Println(search([]int{4,5,6,7,0,1,2}, 3)) // 输出 -1 fmt.Println(search([]int{1}, 0)) // 输出 -1 }
关键点解析
- 有序区间的判定:通过
nums[left]和nums[mid]的比较确定哪一部分是有序的。 - 边界条件处理:例如
nums[left] <= nums[mid]中的等号处理,覆盖了左半部分为单元素的情况(如left == mid)。 - 旋转特性:利用旋转后数组的局部有序性,将时间复杂度控制在 O(log n)。

浙公网安备 33010602011771号