简单的迭代法:
int sqrt(int N)
{
for (int i = 1; i <= N / 2; i++)
{
if(i * i == N ) {
return i;
}
if (i * i < N && (i + 1) * (i + 1) > N) {
return i;
}
}
}
折半迭代法(老师给的方法):
int sqrt(int N)
{
int first = 1, last;
while(1) {
last = N / first;
first = (first + last) / 2;
if (first == last || first == last - 1) {
return first;
}
}
return 0;
}
关于折半法的解释:
从 last = N / first
可以看出 N = first * last,结合下面的 first = (first + last) / 2
可知,每一次循环都会把寻找的数的数量规模缩减为原来的一半,我们简单思考一下,先来两个实例帮助理解:
求 20 的整数平方根:
first | last |
---|---|
1 | 20 |
10 | 2 |
6 | 3 |
4 | 5 |
求 25 的整数平方根:
first | last |
---|---|
1 | 25 |
13 | 1 |
7 | 3 |
5 | 5 |
我们知道,每一次迭代的时候,first和last的乘积都是N,在不能恰好开方的时候,如果last - first != 1,那么我们所求的最后的结果必定存在于first和last之间,然后我们再在下一次的迭代中将last置为N/first,first置为first和last的中间值,每一次的迭代我们都在向最终的first和last接近,使得first * first < N, last * last > N,同时last - first == 1,此时first就是我们所要求的结果。对于恰好能开方的情况,就可以同理了。
此算法时间复杂度为 (O(log N))
更新:
同样是折半查找,我觉得下面的算法更容易理解一些(参考了 LeetCode 的题解):
public int mySqrt(int x) {
if (x == 1) {
return 1;
}
int min = 0;
int max = x;
while (max - min > 1) {
int m = (max + min) / 2;
if (x / m < m) { // 这里也可以用乘法,应该要更快一点
max = m;
} else {
min = m;
}
}
return min;
}
注意,这里是 Java 代码。