携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
二分法
二分法我们应该都很熟悉了,它的主要原理就是对一堆数据以中间值为分割点,分为左右两部分,再与目标进行对比,舍弃掉明显不符合的那部分,从而不断来缩小检索范围,直到找到或接近想要的结果。
但要使用二分法,需要满足一定的条件:
- 存在上下边界:不存在上下边界,中间值也无从谈起
- 单调递增或递减:如果是杂乱无章的数据,取中间值也就没有意义
- 能够通过索引访问:整个过程需要不断寻找中间值
x的平方根
描述
计算一个非负整数的平方根,计算记过舍弃小数,仅保留整数。如:
输入:x = 4
输出:2
输入:8
输出:2 // 8的平方根约等于2.8284271247461903,取整数部分2
分析
首先,当然不允许使用语言的内置函数(像Math.sqrt(x))来执行。
先做个简单过滤,如果x的值是0和1,则直接返回x;
我们可以考虑用二分法来不断的逼近这个值,初始边界值取[0, x],然后不断通过中间值的平方和目标值x进行比较:
- 如果mid²等于x,则返回中间值
- 如果mid²小于x,则左边界值设置为mid,说明结果值要大于mid,继续循环比较
- 如果mid²大于x,则右边界值设置为mid,说明结果值要小于mid,继续循环比较
代码
var mySqrt = function(x) {
if (x === 0 || x === 1) return x
let left = 0
let right = x
while (right - left > 1) {
let mid = Math.floor((left + right) / 2)
const midSqu = mid * mid
if (midSqu === x) {
return mid
} else if (midSqu < x) {
left = mid
} else {
right = mid
}
}
return left
};
这里有个地方需要注意:取中间值mid,如果直接用(left + right)/2,可能会不断产生小数。因为在本题中我们仅取整,并且是向下取整,那我们在获取mid值的时候,就直接通过Math.floor(mid)向下取整。