同样是对于区间的处理问题,可以参照上一题704的思路,稍加进行修改
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
int pos = left+(right-left)/2;
//先排除在序列外的数
if(target<nums[0]){
return 0;
}else if(target>nums[right]){
return nums.length;
}
//二分查找,如果在序列以内,直接返回
while(left<=right){
pos = left+(right-left)/2;
if(target>nums[pos]){
left=pos+1;
}else if(target<nums[pos]){
right=pos-1;
}else{
return pos;
}
}
//退出while循环时,表明这个数出现在了pos两边而不在序列内部
if(target<nums[pos]){
return pos;
}else{
return pos+1;
}
//或者直接写为return right+1
}
}
由于是右闭区间,所以结果直接返回right+1,可以不用pos判断
参考代码随想录网站,还有其余做法,可以不用搜寻第一次出现位置,直接查找左右区间
方法一(有修改,网站代码和我实际验证不同)
这个做法差不多是,从中间往两头逼近端点,寻找的边界包含target
class Solution {
public int[] searchRange(int[] nums, int target) {
//大体思想还是使用二分查找
//1.该元素在数组范围外
//2.该元素在数组范围中,但不在数组内
//3.该元素在数组内
int lpos=findleft(nums,target);
int rpos=findright(nums,target);
return new int[]{lpos,rpos};
}
int findleft(int[]nums,int target){//此处寻找的边界包含=target
int left=0;
int right=nums.length-1;
int middle=left+(right-left)/2;
while(left<=right){
middle=left+(right-left)/2;
if(nums[middle]>=target){
right=middle-1;
}else{
left=middle+1;
}
}
//找到最左端点时,right左移,此时left为有效位置
if(left>=0&&left<nums.length&&nums[left]==target){//情况三
return left;
}
return -1;//情况一和情况二
}
int findright(int[]nums,int target){
int left=0;
int right=nums.length-1;
int middle=left+(right-left)/2;
while(left<=right){
middle=left+(right-left)/2;
if(nums[middle]<=target){
left=middle+1;
}else{
right=middle-1;
}
}
//当找到右端点时,left右移,right值有效
if(right>=0&&right<nums.length&&nums[right]==target){//情况三
return right;
}
return -1;//情况一和情况二
}
}
方法二 这个做法等于是从两边往中间逼近,寻找边界不包含target
class Solution {
public int[] searchRange(int[] nums, int target) {
//情况一,元素在数组范围外,lpos和rpos都会返回-2
//情况二,元素在数组范围内,但不在数组内,
//情况三,元素在数组内,应该返回lpos+1,rpos-1
int lpos=findleft(nums,target);
int rpos=findright(nums,target);
if(lpos==-2||rpos==-2){
return new int[]{-1,-1};
}
if(rpos-lpos>1){
return new int[]{lpos+1,rpos-1};
}
return new int[]{-1,-1};
}
int findleft(int[]nums,int target){
int left=0;
int right=nums.length-1;
int middle=left+(right-left)/2;
int lpos=-2;
while(left<=right){
middle=(left+right)/2;
if(nums[middle]<target){
left=middle+1;
}else{
right=middle-1;
lpos=right;//当逼近到最左位置时候,lpos会在目标元素的左边
}
}
return lpos;
}
int findright(int[]nums,int target){
int left=0;
int right=nums.length-1;
int middle=(left+right)/2;
int rpos=-2;
while(left<=right){
middle=(left+right)/2;
if(nums[middle]>target){
right=middle-1;
}else{
left=middle+1;
rpos=left;
}
}
return rpos;
}
}
好像可以把左右边界放到一个函数里解决,但是,让我练练ORZ