17在排序数组中查找元素的第一个或最后一个位置
题目描述:
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
思路:
数组为有序数组,且复杂度要求为log(n),可以立刻联想到使用二分法查找,我的思路是直接使用二分法查找到一个与目标值相同的元素,而后分别往左和往右拓展,比较暴力。
每次在写二分时总是会出现一些小错误,比如while中条件常常写成<
边界修改时出错。所以特地看了一下二分查找的具体视频,二分查找中一个模板蓝红染色法做了简单整理。
代码:
public static int[] searchRange(int[] nums,int target){
int[] res = {-1,-1};
if(nums.length==0){
return res;
}
if(nums.length==1){
if(nums[0]!=target)return res;
else{
res[0]=0;
res[1]=0;
return res;
}
}
int l = 0;
int r = nums.length -1;
int mid = -1;
int index = -1;
while(l<=r){
mid = (r + l)/2;
if(nums[mid]==target){
index = mid;
break;
}
if(nums[mid]>target)r=mid-1;
if(nums[mid]<target)l=mid+1;
}
if(index==-1)return res;
for (int i = index; i >= 0 ; i--) {
if(nums[i]!=target){
res[0]=i+1;
break;
}
if(i==0)res[0]=0;
}
for (int i = index; i < nums.length; i++) {
if(nums[i]!=target){
res[1]=i-1;
break;
}
if(i== nums.length-1)res[1] = nums.length-1;
}
return res;
}
题解中比较简洁的代码:
public int[] searchRange(int[] nums, int target) {
//初始数组-1,-1
int[] res = new int[]{-1,-1};
int l = 0;
int r = nums.length-1;
while(l <= r){
int mid = (l + r)/2;
if(nums[mid] == target){
int left = mid;
int right = mid;
while(left-1 >= 0 && nums[left-1] == target)left--; //找左边界
while(right+1 < nums.length && nums[right+1] == target)right++; //找右边界
res[0] = left;
res[1] = right;
return res; //返回答案数组
}else if(nums[mid] > target){
r = mid-1;
}else{
l = mid+1;
}
}
return res;
}
二分查找:
解题用到二分查找的时候总是遇到各种各样的问题:
1.while中是小于还是小于等于
2.陷在while循环出不去
3.当数组不存在目标结果如果判断结束循环的条件
4.边界问题,比如更新l和r时,应该等于mid还是mid+1或者mid-1
B站up主五点七边给出的蓝红染色法
左指针从-1开始,右指针从nums.length开始
跳出循环的条件是l+1=r,即所有数值均被染色
更新边界时,赋的值直接为mod
最后根据题目条件返回l或r