模板题目:Binary Search (35. Search Insert Position)
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
就是找插入的位置 一个最最最最基本的二分查找 但是这只是最简单的情况 还有许多情况需要添加进去。
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) return mid;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low;//如果没有的话 low最终将停在第一个大于target的index上。 我们这样想:如果找不到了 那么low high 最后停在同一个位置 这个位置要么是最后一个小于target的地方 要么是第一个target的地方 那么到底是哪个呢?我们看最后不是return low吗 那我们直接看前面当什么情况下low会动 一看 当A【mid】<target的时候low会动 low会往后面移动一位 这就意味着我从小于target的index移动到了大于target的index.所以如果我们找不到target的话 所返回的就是第一个大于target的地方 正好对应题目含义 我们返回这个应该插入的地方
}
补充说明:
对于这种二分查找的问题
首先我们要把看起来不像是二分查找的题目转化为可以使用二分查找的思想的思路。
但是转化过来的 最后要输出的样式千奇百怪
但是不管怎么样 我们要始终坚持tight bound 就是说
low = 0; right = nums.length - 1;
基于上面题目给出的想法 我们可以快速得到我们想要的插入额点,但是有几个问题 如果有元素重复怎么办呢?这样的话我们找第一个大于的点怎么找呢?如果我们想找第一个大于等于的点怎么办呢?
我们来系统的想一下我们都需要找求哪些东西(默认有重复的)
找最后一个小于 最后一个小于等于 第一个大于 第一个大于等于。
当然 我们可以用别的方式来想这四个点 看下面的序列
1 2 3 3 3 3 3 3 4 5 target是3
那么上面这四个点从左到右分别为:
最后一个小于 第一个大于等于 最后一个小于等于 第一个大于
现在 我们的基础代码改了:
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) high = mid - 1; //我们自然不能动low因为Low可能就在边界上 一调下界可能直接把我们的正确结果给跳过去了 并且mid动了也没啥用 所以只能动high 仔细想一下也很合理 我们是往前找 所以下界这个时候是万万不能动的 //关于这个地方到底是high = mid - 1还是low = mid + 1,要看我们是想找(最后一个小于/第一个大于等于 还是 最后一个小于等于/第一个大于)如果是前者 就往前怼 也就是high = mid - 1,如果是后者 就往后怼 就是low = mid + 1;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low; //第一个大于等于的点(就是说我们要么找到等于的初始点 要么找到那个大于target的第一个点)所以我们如果想要找最后一个小于target的点 就直接low - 1
}
这个基础代码 会使得我们最后返回的 是第一个大于等于target的index.(至于为什么是这样 请看附录)
所以我们想找最后一个小于等于target的index,就直接把最后return low变成return low - 1就行了
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) high = mid - 1;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low - 1;
}
所以我们想找最后一个小于等于target的(从左往右数第三个)就直接
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) low = mid + 1;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low - 1;
}
所以我们想找第一个大于target的(从左往右数第四个)就直接
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) low = mid + 1;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low;
}
如果不想废话 不想再搞一遍原理就可以使用 请看下面:
基础代码:
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) return mid;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low;
}
首先确定我们要得到的是下面哪个index
最后一个小于 第一个大于等于 最后一个小于等于 第一个大于
然后我们对上面的代码修改只需修改两个地方来得到上述四个值
if(A[mid] == target) return mid;
return low;
首先我们要确定我们始要前两个还是后面两个。
如果要前面两个 那么我们就收缩上界:if(A[mid] == target) return mid; =》 if (A[mid] == target) high = mid - 1;
如果要后面两个 那么我们就收缩下界:if(A[mid] == target) return mid; =》 if (A[mid] == target) low = mid + 1;
然后 进一步细分 选择return low还是low-1就看你需要返回前面那个还是后面那个。
附录:
首先 我们来看找第一个大于的点,虽然这个看上去像是找到插入点 但是实际上不一样 因为在之前找插入点代码中 一旦我们满足 if(A[mid] == target) return mid;就立刻返回,而不管这个是不是是不是第一个。所以我们可以对上面的代码做一些修改。
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) high = mid - 1; //我们自然不能动low因为Low可能就在边界上 一调下界可能直接把我们的正确结果给跳过去了 并且mid动了也没啥用 所以只能动high 仔细想一下也很合理 我们是往前找 所以下界这个时候是万万不能动的
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low;
}
当然了 如果我们确定没有重复的 就不用这么麻烦了。
根据上面的思路 如果我们想找第一个大于等于target的点 那我们只需要:
首先 我们把最基础的摆上来:
public int searchInsert(int[] A, int target) {
int low = 0, high = A.length-1;
while(low<=high){
int mid = (low+high)/2;
if(A[mid] == target) return mid;
else if(A[mid] > target) high = mid-1;
else low = mid+1;
}
return low;
}
然后我们首先要修改return low为return high因为现在我们要返回那个大于等于的点。
然后我们要处理有重复的情况:把 if(A[mid] == gtarget) return mid;改成 if(A[mid] == target) low = mid + 1;;
还有一个情况 看看我们是输出那个index 还是那个要求的值。

浙公网安备 33010602011771号