提示:本题是系列LeetCode的150道高频题,你未来遇到的互联网大厂的笔试和面试考题,基本都是从这上面改编而来的题目
互联网大厂们在公司养了一大批ACM竞赛的大佬们,吃完饭就是设计考题,然后去考应聘人员,你要做的就是学基础树结构与算法,然后打通任督二脉,以应对波云诡谲的大厂笔试面试题!
你要是不扎实学习数据结构与算法,好好动手手撕代码,锻炼解题能力,你可能会在笔试面试过程中,连题目都看不懂!比如华为,字节啥的,足够让你读不懂题
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
在有序数组arr中
找>=x最左的位置【满足条件,记录当前位置i,使劲往左搜】
如果找到中间位置[M]
直到L>R停止搜索
//算法原型:
//找>=x最左的位置【满足条件,记录当前位置i,使劲往左搜】
//如果找到中间位置[M]
//如果找到中间位置[M]>=x,可能M左边还有>=x的呢,先记下当前达标位置i=M,下次让R=M-1
//直到L>R停止搜索
public static int findBigEqual(int[] arr, int L, int R, int x){
int i = -1;//默认没有
while (L <= R){
int M = L + ((R - L) >> 1);
if (arr[M] < x) L = M + 1;
else {
i = M;
R = M - 1;//使劲往左找
}
}
return i;
}
找<=x最右的位置【满足条件,记录当前位置j,使劲往右搜】
可以二分查找
如果找到中间位置[M]<=x,可能M右边还有<=x的呢,先记下当前达标位置j=M,下次让L=M+1
如果找到中间位置[M]>x,说明x在M左边,下次让R=M-1
直到L>R停止搜索
手撕代码:
//找<=x最右的位置【满足条件,记录当前位置j,使劲往右搜】
//可以二分查找
//如果找到中间位置[M]<=x,可能M右边还有<=x的呢,先记下当前达标位置j=M,下次让L=M+1
//如果找到中间位置[M]>x,说明x在M左边,下次让R=M-1
//直到L>R停止搜索
public static int findLessEqual(int[] arr, int L, int R, int x){
int i = -1;//默认没有
while (L <= R){
int M = L + ((R - L) >> 1);
if (arr[M] > x) R = M - 1;
else{
i = M;
L = M + 1;//使劲往右找
}
}
return i;
}
比如找target=6
(1)则找<=6的最右的位置R
(2)找>=6最左的位置L
看看LR不是-1,就是找到了,再看L<=R而且L处是target,R处也是target的话,绝对完美L–R就是结果
否则就没有
手撕代码
public int[] searchRangeReview(int[] nums, int target) {
//比如找target=6
if (nums == null || nums.length == 0) return new int[] {-1, -1};
int N = nums.length;
int[] ans = new int[2];//0左边界,1右边界
ans[0] = -1;
ans[1] = -1;//,默认没有
//(2)找>=6最右的位置R
int L = findBigEqual(nums, 0, N - 1,target);
//(1)则找<=6的最右的位置i
int R = findLessEqual(nums, 0, N - 1, target);
//反正L和R要么同时为-1,要么不会为-1
//你看看ij处是6吗?是就是j--i,//否则就是i-1,j+1
if (L != -1 && R != -1){
ans[0] = L <= R && nums[L] == target ? L : -1;
ans[1] = L <= R && nums[R] == target ? R : -1;
}
return ans;
}
绝对完美
测试一把:
public static void test(){
int[] arr = {5,7,7,8,8,10};
int target = 7;
Solution solution = new Solution();
int[] res = solution.searchRange(arr, target);
System.out.print(res[0] + " " + res[1]);
System.out.println();
res = solution.searchRangeReview(arr, target);
System.out.print(res[0] + " " + res[1]);
}
public static void main(String[] args) {
test();
}
1 2
1 2
提示:重要经验:
1)算法原型:在有序数组中,二分查找>=x,最左位置,<=x最右位置,使劲朝着一边找,之前记录已经找到的位置i
2)比如找target(1)则找<=6的最右的位置R,(2)找>=6最左的位置L,如果LR不是-1,必然L<=R,必然就是找到了的
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。