方法一:Binary Search
这道题目是一个典型的binary search问题,看似比较简单,但其实陷阱也不少。一开始直接从1到x使用binary search来寻找答案,但结果竟然TLE了,仔细想想可以发现,我们并不用从1到n寻找,只用从1到n / 2 + 1就可以了,这样就省掉了一半的时间,妈妈再也不用担心我TLE啦!可是在LeetCode上遇到x很大的test case的时候,结果仍然是错的,因为这里没有考虑到int溢出的问题,为了解决这个,我们可以使用long long,也可以使用x / mid == mid来判断,这里使用了后者,因为可以节省些空间(==.....),时间复杂度为O(logn),代码如下:
public class Solution {
public int mySqrt(int x) {
if(x < 0) return x;
// Use binary search to find square root
int left = 1;
int right = x / 2 + 1;
while(left <= right){
int mid = (left + right) / 2;
if(x / mid == mid) return mid;
else if(x / mid > mid) left = mid + 1;
else right = mid - 1;
}
return right;
}
}
方法二:Newton's Method
public class Solution {
public int mySqrt(int x) {
if(x < 0) return x;
double last = 0;
double res = 1;
while(res != last){
last = res;
res = (res + x / res) / 2;
}
return int(res);
}
}
这里我们结束循环的判断是判断当前的x和上一个迭代中x的差是不是小于某个极小值 。 这里注意一个小问题,就是在java中我们可以用==来判断两个double是否相等,而在C++中我们则需要通过两个数的绝对值差小于某个极小值来判断两个double的相等性。实际上两个double因为精度问题往往是不可能每一位完全相等的,java中只是帮我们做了这种判定。所以当res == last的时候,res和last是小于某个非常小的值的,也就是达到了循环结束的条件。
知识点:
1. 当程序中出现x * x及增长速度大于x^2的计算的时候(比如x^4,指数函数)之类的情况,要尤其注意使用int会不会造成溢出的问题
2. 使用二分搜索的时候,要结合题目的情况,注意搜索的范围是不是可以优化,比如这道题目,如果搜索1到n的话,就会另外白白浪费很多的时间