数组在旋转后,保持局部有序的状态,比如说[4, 5, 6, 7, 0, 1, 2, 3],l=0, r= 7, mid=3,nums[l] < nums[m],说明左半部分[4, 5, 6, 7]是有序的,右半部分[7, 0, 1, 2, 3]是无序的。
- 为了应用二分查找,优先去有序的那一半,需要将nums[m]和nums[l]进行比较。
- 如果能确认
nums[m] < target <= nums[r]或nums[l] <= target < nums[m],按照二分查找的逻辑设置l和r即可,[l, m - 1]或[m + 1, r]。 - 否则,说明target不在该区间中,如果不在左半区间,l = m + 1;如果不在右半区间,r = m - 1。
- 把2和3结合起来,完成if-else的逻辑。
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function (nums, target) {
let l = 0;
let r = nums.length - 1;
while (l <= r) {
const m = Math.floor((l + r) / 2);
if (nums[m] === target) return m;
// 左半边为递增区间
// 此处的等号是必须的,因为m可能等于l,比如[3,1],l = m = 0, r = 1
// 此时[l,m]是递增区间,如果认为[m,r]是递增区间,就错了
if (nums[m] >= nums[l]) {
if (target >= nums[l] && target < nums[m]) {
r = m - 1;
} else {
// target不在该区间内; 二分查找,target单纯比nums[m]大
l = m + 1;
}
}
// 右半边为递增区间
else {
if (target <= nums[r] && target > nums[m]) {
l = m + 1;
} else {
// target不在该区间内; 二分查找,target单纯比nums[m]小
r = m - 1;
}
}
}
return -1;
};