一、关键洞察
旋转数组的二分和普通二分只有一个区别:普通二分我们知道整个数组有序,旋转数组中必有一侧是有序的。
判断哪一侧有序,然后看 target 是否在这一侧。
二、代码实现
javascript
var search = function(nums, target) {
let left = 0, right = nums.length - 1;
while (left <= right) {
const mid = left + Math.floor((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;
};
三、关键细节
nums[left] <= nums[mid] 判断左侧是否有序。如果左侧有序且 target 在 left 到 mid 之间,收缩到左侧,否则去右侧。
当 nums[left] > nums[mid] 时,左侧无序则右侧一定有序,同理处理。
用 <= 而不是 <------当 left === mid 时,nums[left] <= nums[mid] 为 true,左侧被判定为有序(一个元素天然有序)。
四、复杂度
O(log n) 时间,O(1) 空间。
五、总结
- 旋转数组二分的关键:必有一侧有序
- 判断哪一侧有序,再判断 target 是否在其中
- 和普通二分的区别只多了一个条件分支
- 不包含重复数字时,numsleft <= numsmid 即可判断