69. x 的平方根
思路:
首先最简单的暴力法:
public int mySqrt(int x) {
long i = 0;
long n = 0;
while(n<=x){
i++;
n = i*i;
}
return (int)i-1;
}
然后就是二分法了,我第一版本是这样的:
public int mySqrt(int x){
int left = 0;
int right = x/2+1;// 为了照顾到 1 把右边界设置为 x / 2 + 1
while(left < right){//死循环
int mid = left + (right - left)/2;
if(mid*mid > x){
right = mid-1;
}else{
left = mid;
}
}
return left;
}
但是这样出现了死循环,例如测试用例4,mid最后会和left相等并且一直停留在2,right会一直在3,所以无法退出循环。问题就出在mid已经等于正确答案的时候没有退出循环,所以多加一个相等时的判断就好啦。另外,针对特殊测试用例,例如 2147395599 要把搜索的范围设置成长整型:
public int mySqrt(int x){
long left = 0;
long right = x/2+1;
while(left < right){
long mid = left + (right - left)/2;
if(mid*mid > x){
right = mid-1;
}else if(mid*mid == x){
return (int)mid;
}else{
left = mid;
}
}
return (int)left;
}
但是还是错了😭,连测试用例1都过不了,因为left和mid卡在0,right卡在1,都无法更新,但正确答案是1却一直达不到,所以这里mid一定取右中位数,如果取左中位数,代码会进入死循环:
public int mySqrt(int x){
long left = 0;
long right = x/2+1;
while(left < right){
long mid = left + (right - left + 1)/2;
if(mid*mid > x){
right = mid-1;
}else{
left = mid;
}
}
return (int)left;
}