本题本质上还是对二分查找的应用,区别在于当判断nums[mid]==target时,普通二分查找直接返回,而本题目却依旧要移动边界。
把问题简化一下,找第一个位置和最后位置分别用一次二分查找,在left=right时跳出循环。
先看寻找左边界,当目标值与mid对应的相同时,让右边界移动到mid,因为此时mid右边的所有值都是大于等于目标值,寻找的是最左值所以将左边部分舍去。
var searchLeft= function(nums,target){
//[]区间
let left=0,right=nums.length-1;
while(left<right){
let mid=Math.floor((left+right)/2);
if(nums[mid]==target){
right=mid;
}else if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
if(nums[left]==target){
return left;
}
return -1;
}
寻找右边界,不同于左边,寻找右边界时mid=Math.floor((left+right+1)/2),为了避免死循环,当剩余数组数量是偶数时,会将mid落到偏右边的位置
var searchRight= function(nums,target){
//[]区间
let left=0,right=nums.length-1;
while(left<right){
//为了避免死循环,当剩余数组数量是偶数时,会将mid落到偏右边的位置
let mid=Math.floor((left+right+1)/2);
if(nums[mid]==target){
left=mid;
}else if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
if(nums[left]==target){
return left;
}
return -1;
}
整体代码如下
//二分查找,左闭右闭区间
//寻找第一个等于target的位置leftIx以及
//第一个大于target的位置
var searchLeft= function(nums,target){
//[]区间
let left=0,right=nums.length-1;
while(left<right){
let mid=Math.floor((left+right)/2);
if(nums[mid]==target){
right=mid;
}else if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
if(nums[left]==target){
return left;
}
return -1;
}
var searchRight= function(nums,target){
//[]区间
let left=0,right=nums.length-1;
while(left<right){
//为了避免死循环,当剩余数组数量是偶数时,会将mid落到偏右边的位置
let mid=Math.floor((left+right+1)/2);
if(nums[mid]==target){
left=mid;
}else if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
if(nums[left]==target){
return left;
}
return -1;
}
var searchRange = function(nums, target) {
let leftIx=searchLeft(nums,target);
let rightIx=searchRight(nums,target);
if(leftIx==-1){
return [-1,-1]
}
return [leftIx,rightIx]
};