搜索旋转排序数组:二分查找的巧妙应用
今天我在LeetCode上解决了"搜索旋转排序数组"这个问题(题目编号33)。下面我将分享我的解题思路和代码实现。
解题思路
虽然数组被旋转了,但它仍然部分有序,这提示我们可以使用二分查找的变种来解决这个问题。关键在于如何判断目标值位于哪一部分。
- 常规二分查找 :首先计算中间索引
mid
。 - 判断有序部分 :
- 如果
nums[left] <= nums[mid]
,说明左半部分是有序的 - 否则,右半部分是有序的
- 如果
- 在有序部分中判断目标值的位置 :
- 如果在有序部分范围内,则在该部分继续搜索
- 否则,在另一部分搜索
代码实现
java
class Solution {
public int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right){
int mid=(right-left)/2+left;
if(nums[mid]==target){
return mid;
}
if(nums[0]<=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
时使用(right - left) / 2 + left
而不是(left + right) / 2
。 - 有序部分判断 :通过比较
nums
和nums[mid]
来确定哪一部分是有序的。 - 目标值范围判断:在确定有序部分后,检查目标值是否在该部分范围内,以决定搜索方向。
复杂度分析
- 时间复杂度:O(log n),因为每次都将搜索范围减半。
- 空间复杂度:O(1),只使用了常数级别的额外空间。
=========================================================================
寻找旋转排序数组中的最小值:二分查找的精妙应用

解题思路
旋转后的数组虽然不再是完全有序,但仍然保持部分有序的特性,这使得我们可以使用二分查找算法高效解决:
- 理解旋转特性:旋转后的数组分为两个有序部分,最小值位于两个有序部分的交界处
- 二分查找的关键 :
- 比较中间元素和右边界元素
- 如果中间元素小于右边界元素,说明最小值在左半部分(包括中间元素)
- 如果中间元素大于右边界元素,说明最小值在右半部分(不包括中间元素)
- 循环终止条件:当左指针和右指针相遇时,它们指向的位置就是最小值
代码实现
java
class Solution {
public int findMin(int[] nums) {
int left=0;
int right=nums.length-1;
//当使用 left < right 作为循环条件时,循环结束时 left 和 right 指向同一个位置,而这个位置就是我们要找的目标
while(left<right){
int mid=(right-left)/2+left;
if(nums[mid]<=nums[right]){
right=mid;
}else if(nums[mid]>=nums[right]){
left=mid+1;
}
}
//当 nums[mid] > nums[right] 时,说明最小值在右半部分,且 mid 位置肯定不是最小值,所以应该设置 left = mid + 1
//当 nums[mid] < nums[right] 时,说明最小值在左半部分,且 mid 位置可能是最小值,所以应该设置 right = mid
return nums[left];
}
}
关键点解析
- 循环条件选择 :使用
left < right
而不是left <= right
,确保最终left和right会相遇 - 边界处理 :
- 当
nums[mid] <= nums[right]
时,最小值在左半部分(包括mid) - 当
nums[mid] > nums[right]
时,最小值在右半部分(不包括mid)
- 当
- 指针移动逻辑 :
- 最小值在左侧时:
right = mid
(mid可能是最小值) - 最小值在右侧时:
left = mid + 1
(mid不可能是最小值)
- 最小值在左侧时:
- 终止条件 :当
left == right
时,指向的就是最小值
复杂度分析
- 时间复杂度:O(log n),每次迭代都将搜索范围减半
- 空间复杂度:O(1),只使用了常数级别的额外空间
实例演示
假设输入数组为[4,5,6,7,0,1,2]
:
- 初始:left=0, right=6, mid=3 (值为7)
- 7 > 2 → 最小值在右侧 → left=mid+1=4
- 第二轮:left=4, right=6, mid=5 (值为1)
- 1 <= 2 → 最小值在左侧 → right=5
- 第三轮:left=4, right=5, mid=4 (值为0)
- 0 <= 1 → 最小值在左侧 → right=4
- 循环结束:left=4, right=4 → 返回nums=0
总结
这道题目展示了二分查找算法的强大适应能力。即使数组不是完全有序,通过巧妙地比较中间元素与边界元素的关系,我们仍然可以在对数时间内找到最小值。这种思路在实际应用中非常有用,特别是在处理部分有序或旋转后的数据时。
关键启示:
- 理解旋转数组的特性:由两个有序部分组成
- 通过比较中间元素和边界元素确定最小值的位置
- 精心设计的指针移动逻辑确保高效搜索
掌握了这种二分查找的变种,我们能够解决更多类似的搜索问题,提高算法解决实际问题的能力。