题目
思路
找到分界点的位置,比如[4, 5, 6, 7, 0, 1, 2], 找到0,这样就分成了两段有序数组
旋转点的位置并不是分界点,nums[0]才是
根据nums[0]和target的大小判断target应该在哪一个区间里
注意,可以从位置0开始旋转,也就是说,除了两段递增序列之外,还可能出现只有一段递增序列
-
为什么right要采取right = nums.length; 这种不常规的写法?
这是针对只有一段递增序列的情况来算的。比如[4, 5, 6] 它的分界点应该在6之后,也就是对应位置3的地方。但是如果仅仅是right = nums.length - 1; 那么left在结束时应该正好走到和right相同的地方,也就是只能走到6。 -
能不能在寻找分界点的时候改成left <= right?
不能,会出现死循环。按理来说,left 会停在分界点,比如说[4, 5, 6, 0, 1, 2], left, right都停在0的时候,恰好会执行nums[mid] < nums[0],会出现死循环
代码
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function(nums, target) {
//先找到分割位置
//分割位置左侧,全部大于等于nums[0],分割位置以及右侧,全部小于nums[0]
let left = 0;
let right = nums.length;//注意这个地方,right必须让出来一位,不然left结束时最远走到和right相同的地方,不适用于只有一段递增的情况
let mid;
while (left < right){
mid = left + Math.floor((right - left)/2);
if (nums[mid] < nums[0]){
right = mid; // 如果mid正好是分割位置的话,right = mid - 1就会正好跳过分割位置
}else{ //nums[mid] >= nums[0]
left = mid + 1;
}
}
let pos = left;//分割位置在pos,[pos, nums.length - 1]是第二段,[0, pos - 1]是第一段
console.log(pos)
//通过nums[0]数值判断target在哪一段
if (target >= nums[0]){//在第一段
left = 0;
right = pos - 1;
}else{//在第二段
left = pos;
right = nums.length - 1;
}
while(left <= right){
mid = left + Math.floor((right - left)/2);
if (nums[mid] === target){
return mid;
}
else if(nums[mid] > target){
right = mid - 1;
}
else{
left = mid + 1;
}
}
return -1;
};