题目:
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。
题目意思很简单,调库函数肯定不行,那么就能想到二分。
因为我们要的结果总是左边界
意思就是比如 5 的开方,2平方小,3平方大了,我们希望要的结果是 2 ,那么就是总要在左半部分更新答案,当 i > j 的时候跳出循环,就是正确答案了。
为了防止溢出,判断的时候乘法改成用除法,这样就不用 long 转型,那么改用除法就有分母为0的问题,所以我们将 x=0 和 x=1 的情况单独处理,这样左边界直接可以取到 1,右边界可以直接取到x/2.。
用到的是模板一,模板来源:
二分查找简介、二分查找的三类模板总结
class Solution {
public int mySqrt(int x) {
if( x<2 )return x;
int i = 1;//去除了0和1的情况,i可以从1开始,避免x/mid出现分母为0
int j = x/2;//去除了0和1的情况,j可以从x/2开始
int ans = 0;
while( i <= j ){
int mid = i + (j-i)/2;
if( mid <= x/mid){
ans = mid;
i = mid+1;
}else{
j = mid-1;
}
}
return ans;
}
}
虽然归类到了第一类基础模板,但是还是在二分里面做了改变,那就是 <= 的时候,都更新答案并且做了 ans 的更新。
如果严格按照基础模板,写出来应该是需要后处理的,在严格等于的情况只能处理一部分:
class Solution {
public int mySqrt(int x) {
if( x<2 )return x;
int i = 1;
int j = x/2;
while( i <= j ){
int mid = i + (j-i)/2;
if( mid == x/mid && x%mid == 0 ){
return mid;
}
if( mid < x/mid){
i = mid+1;
}else{
j = mid-1;
}
}
if( i<=x/i )return i;//需要后处理
return i-1;
}
}