问题为:给定一个按照升序排列的整数数组 nums
,和一个目标值 target
。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target
,返回 [-1, -1]
。
具体思想为:
对于题目中的进阶要求中有再lgn时间内解决,因此首先考虑的就是二分法查找,首先基于如果数组中元素为升序排列,且数组中元素各不相同的情况下,首先设置循环判定条件while(left<=right)之后对于循环内的判定条件,先判断nums[mid]==target是否成立,若成立则直接return mid即可,若不成立,则判断nums[mid]>target是否成立,若成立则表明target可能在mid的左边区间(之所以为可能是因为target也可能不在nums数组内),则将区间大小缩小为左边区间的大小即令right=mid-1;若不满足nums[mid]>target即target>nums[mid]表明target可能在mid的右边区间内,于是要将整个的区间大小缩小为右边区间的大小即可,即为left=mid+1;之后对于缩小后的区间若仍然满足left<=right则继续执行循环的条件,否则则直接return -1;表明已经退出了循环即递增的数组内不存在target元素,故而返回-1。
上述是基于不存在重复元素的基础上的最基本的二分查找法,但是该问题的数组中允许元素是重复的,所以可以这样设置,设置两个函数public int Firstnum(int[] nums,int target)与public int Lastnum(int[] nums,int target)来确定该target的首个相等处的下标和最后一次相等处的下标,如实例为nums = [5,7,7,8,8,10], target = 8,对于Firstnum可以先直接按照最原始的二分法书写代码,但对于其中nums[mid]==target的情况要进行修改,即若满足该情况时,要判断mid==0或者nums[mid-1]!=nums[mid]是否成立,若二者有一个成立,则表明该mid一定就是首个相等处的下标例如实例中的下标3即为此种情况.如果不满足二者中的任意一种情况,即表明该target不是要寻找的数,要寻找的数一定在该mid的左侧区间,即缩小区间范围为该mid的左侧区间,即令right=mid-1;
同理对于Lastnum的情况类似于上方的Firstnum函数对于nums[mid]==target的情况,的判定双条件为mid==nums.length-1或nums[mid+1]!=nums[mid]即可,之后若不满足则表明要找的target则在该mid的右侧区间即要令left=mid+1即可实现.
具体代码实现如下所示。
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] ans=new int[2];
int a,b;
a=Firstnum(nums,target);
b=Lastnum(nums,target);
ans[0]=a;
ans[1]=b;
return ans;
}
public int Firstnum(int[] nums,int target){
int left=0,right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
if(mid==0||nums[mid-1]!=nums[mid]){
return mid;
}else{
right=mid-1;
}
}else if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;
}
public int Lastnum(int[] nums,int target){
int left=0,right=nums.length-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target){
if(mid==nums.length-1||nums[mid+1]!=nums[mid]){
return mid;
}else{
left=mid+1;
}
}else if(nums[mid]<target){
left=mid+1;
}else{
right=mid-1;
}
}
return -1;
}
}
对于一般的二分查找法要注意的是,如果目标target不在该升序的数组nums中,并且要插入该nums数组且仍保持数组nums为升序的则target要插入的下标应为left指针当前的值具体分析如下:
在执行完毕二分查找法后,要注意的是,对于找不到数的情况有三种极端1.如果目标target小于数组中所有的值,则left的值0一不会改变,最后要插入的位置也恰好为0故而返回left即可.2如果目标target大于数组中的所有元素,则right值一直不变最后情况为left指向倒数第二个数,right指向最后一个数,mid求出来为left的值,故而nums[mid]<target应执行left=mid+1,的操作即此时left的值为nums.length-1此也为target要插入的下标的值。3.如果查找的target不在该数组内但在该数组的两个数值之间的范围,则最终left与right一定分别指向该两个数,则按照情况2的分析,最后left一定会变成原来right的指针位置的值,因此这也是target应该插入的target所在的下标。故而结合上述三种情况,当target不在nums数组中时,目标值target如果要插入该数组中,则要插入的下标应为二分查找后的left的最后的值.