二分查找,很基础,但是细节又特别多。
二分查找,不难,看着就会,上手就懵逼,细节处理不到位就不能ac。
关于while条件中的,left < right,还是 left <= right,都会影响后续的处理
left <= right
这里主要是看right的边界问题,这里的right处于闭合状态,也就是[left, right],左右闭合,此时在while内部的逻辑中,right也应该是处于闭合的状态,上一轮的mid已经检测过了的地方,此时不应该再检测,所以应该为right = mid - 1
var searchInsert = function (nums, target) {
let left = 0, right = nums.length - 1
while (left <= right) {
let mid = Math.floor((left + right) / 2)
if (nums[mid] === target) {
return mid
} else if (nums[mid] > target) {
right = mid - 1
} else {
left = mid + 1
}
}
return left
};
先说上面这个代码,条件是 left <= right
这里的跳出条件为 left = right + 1
所以这里更适用于查找具体的数字,以及要插入的位置。
[1,2,3,5,6] target = 4时
left = 0, right = 4,mid = 2,nums[mid] = 3
left = mid + 1 = 3,right = 4,mid = 3,nums[mid] = 5
left = 3, right = mid - 1 = 2,此时直接不满足条件,直接跳出循环
返回left = 3
- 在每次循环中,
left和right都可能移动到对方的位置。 - 循环终止时,
left刚好超出right一位,即left = right + 1。 - 适用于需要在循环内
明确找到目标值或在其不存在时返回插入位置的情况。
left < right
这里是左闭右开,也就是[left, right),此时right所在的地方是没有值的,所以在while内的逻辑中,检测过后的right的范围也应该是在mid的位置,这样保证不会漏掉
var searchInsert = function(nums, target) {
let left = 0, right = nums.length;
while (left < right) {
let mid = Math.floor((left + right) / 2);
if (nums[mid] === target) {
return mid;
} else if (nums[mid] > target) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
};
- 查找目标值是否存在:用于需要检查目标值是否存在但不关心其具体位置的情况。
- 查找边界位置:用于寻找特定条件下的边界位置,如最左边或最右边符合条件的位置。
特点
- 在每次循环中,
left和right不会相互越界,即使在最后一次循环时也是如此。 - 循环终止时,
left和right相等,即left = right。 - 适用于寻找满足特定条件的边界位置。