总结
二分查找看起简单,新手就是撸不出来
关键1:中间位置mid = ((right - left) / 2) + left 或 (left + right) / 2 防止溢出
关键2:循环终止判断,while循环,left>=right 就停止
关键3:mid位置不断移动
方法1
- ans的初始化位置不是很好直观理解,也是官方答案的写法
- 中间位置的计算方法:int mid = ((right - left) / 2) + left;其它地方也是这样算
- 第一步转化公式
- 第二步根据转化公式,找到:在一个有序数组中找第一个大于等于 target的下标,等于就是找到了,第一个大于就是插入的位置
/**
* 考虑这个插入的位置 pos,它成立的条件为:
* nnums[pos−1]<target≤nums[pos]
*
* 其中 nums代表排序数组。由于如果存在这个目标值,我们返回的索引也是 pos,因此我们可以将两个条件合并得出最后的目标:
* 「在一个有序数组中找第一个大于等于 target的下标」。
*
* 问题转化到这里,直接套用二分法即可,即不断用二分法逼近查找第一个大于等于 target的下标 。
* 下文给出的代码是笔者习惯的二分写法,ans初值设置为数组长度可以省略边界条件的判断,
* 因为存在一种情况是 target大于数组中的所有数,此时需要插入到数组长度的位置。
*/
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1, ans = n;
while (left <= right) {
int mid = ((right - left) / 2) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
}
方法2
- 返回的是left的值,如果left>right了,这个时候left已经加1了,这个时候left的位置刚好是要插入的位置
- 学习视频:二分查找 红蓝染色法_哔哩哔哩_bilibili
package algorithm.second.array.and.string.topic_LCR068;
/**
* link{https://leetcode.cn/problems/N6YdxV/solutions/1398925/cha-zhao-cha-ru-wei-zhi-by-leetcode-solu-inlw/}
*/
class Solution2 {
/**
*[left,right] 是闭区间
*/
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
/**
*[left,right) 是开区间
*/
public int searchInsert2(int[] nums, int target) {
int left = 0, right = nums.length;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
// return right; 返回 left,right 都可以
}
}