二分法 的使用其实比较受限,最明显的特点是:
绝大情况,查找目标具有单调性质(单调递增、单调递减)
有上下边界,并且最好能够通过index下标访问元素
例如:
在 [1, 2, 3, 4, 5, 6, 7, 8, 9] 中找到 4,若存在则返回下标,不存在返回-1,要求算法复杂度O(logn)
看到上面这题目,O(logn)复杂度的要求,第一反应就是使用二分查找法,怎么做呢?先在图上模拟以下二分法的大概流程:
根据图解
代码如下:
function searchNum (target, nums) {
if (!nums.length) return -1
let left = 0
let right = nums.length - 1
let mid
while (left <= right) {
// >> 1 位运算代替 除2 取整 操作
// 为什么不写成 mid = (left+right)/2 ,因为考虑到left+right的溢出边界情况
mid = left + ((right - left) >> 1)
if (nums[mid] === target) {
return mid
}
if (nums[mid] < target) {
left = mid + 1
}
if (nums[mid] > target) {
right = mid - 1
}
}
return -1
}
小结二分法的套路
我们可以从上面的问题中,看出点二分法的套路出来,二分法是有律可循的,并且可以推导出基础的模板:
let left = start
let right = end
let mid
while (left <= right) {
mid = (left + right) / 2
if (array[mid] === target) {
return result 或者 break down
}
if (array[mid] < target) {
left = mid + 1
}
if (array[mid] > target) {
right = mid - 1
}
}
我们得到二分法的基础模板后,就可以顺势解决 x的平方根 这种类型的题目了ovo
附上 x的平方根 解题代码:
const mySqrt = function(x) {
if (x < 2) return x
let left = 1, mid, right = Math.floor(x / 2);
while (left <= right) {
mid = Math.floor(left + (right - left) / 2)
if (mid * mid === x) return mid
if (mid * mid < x) {
left = mid + 1
}else {
right = mid - 1
}
}
return right
}