题目
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
题目地址:https://leetcode.cn/problems/sqrtx
示例
方法1:暴力循环(蠢)
作者:本人
思路:
求开方?那不是很简单,直接从1开始一个一个试呗,谁的平方==x,那就是谁喽。
class Solution {
public int mySqrt(int x) {
for (int i=1;i<=x;i++){
if (i*i==x)return i;
if (i*i<x && (i+1)*(i+1)>x)return i;
}
return 0;
}
}
提交之后就是失败,因为超时了,因为当x是很大的数字的时候,你一个一个遍历,肯定很费时间。
方法2:二分法
作者:本人
思路:
为了解决超时问题,那我们就用二分法。
最左设置为0,最右设置为x,那中间mid就是 (left+right)/2,如果mid*mid ==x,那就说明找到了结果,如果 <x,那说明中间数mid 太小了,我们放大点,让left移动到mid,反之让right 移动到mid。
一直循环,循环条件是 left必须<right ,还有一种情况是 left 和 right 只相差1,说明真实答案是比left大一点,比right小一点,那就直接返回left即可。
注意
前面我一直是用的 下面这种方式,可是答案就是不通过,提示超时
if (mid * mid == x)return mid;
说明平方有问题,看了网上别人的做法,非常的巧妙,直接将所有的 a * b == c 的模式改成 a == c / b 即可
例如上面就改成
if (mid ==x/mid)return mid;
答案直接通过
class Solution {
public int mySqrt(int x) {
if (x<4 && x>0)return 1;
int left = 0;
int right = x;
while (left<right){
int mid = (left + right)/2;
if (mid ==x/mid)return mid;
if (left+1 == right){
return left;
}
if (mid > x/mid){
right = mid;
}else if (mid < x/mid){
left = mid;
}
}
return 0;
}
}
方法3:二分法(完美版)
思路
与方法2一致,比我的更优秀
作者:力扣:Noble Monster
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;
}
总结
1. 不要再惦记你那个b暴力循环了,真的很蠢,多想想二分法之类的好方法。
2.为了防止溢出,我们可以用 x/m<m 而不是m*m>x