题目:69 x的平方根(easy)
一、题目
Given a non-negative integer x, compute and return the square root of x.
Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned.
Note: You are not allowed to use any built-in exponent function or operator, such as pow(x, 0.5) or x ** 0.5.
Example 1:
Input: x = 4
Output: 2
Example 2:
Input: x = 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since the decimal part is truncated, 2 is returned.
Constraints:
0 <= x <= 231 - 1
二、 思路
其实还是满足二分法的使用条件,数组元素无重复+从小到大排列,只不过数组就是[0,x],判断条件也稍微改变了一下而已。
二、自己写的
1.代码
第一次写
class Solution {
public int mySqrt(int x) {
//必须得用左闭右开的,想想x=1的情况
int left = 0, right = x, mid = 0;
if (x == 1)
return 1;
if (x == 0)
return 0;
while (left < right) {
mid = left + (right - left) / 2;
int r = mid * mid;
// r>x 最终结果一定在当前mid的左边,往左走
if (r > x)
right = mid;
// r<x 不一定,因为example2就说明了小也可能是答案
else if (r < x) {
//如果mid+1的平方大于x了,那当前mid就是output
if ( (mid + 1) * (mid + 1) > x)
return mid;
//否则最终结果一定在当前mid的右边,往右走
else
left = mid + 1;
}
else
return mid;
}
return -1;
}
}
//错误1:提交了两次,WA在两个特殊的例子0和1上,所以0,1做了特殊处理,所以没必要非得左闭右开了
//错误2:这样求r可能数值太大了,溢出了,所以要判断x开平方以后的值和mid比
第二次写
class Solution {
public int mySqrt(int x) {
int left = 0, right = x, mid = 0;
if (x == 1)
return 1;
if (x == 0)
return 0;
while (left < right) {
mid = left + (right - left) / 2;
//把r = mid
// r>x 最终结果一定在当前mid的左边,往左走
if ((x / mid) < mid)
right = mid;
// r<x 不一定,因为example2就说明了小也可能是答案
else if (mid < (x / mid)) {
//如果mid+1的平方大于x了,那当前mid就是output
if ( (mid + 1) > (x / (mid + 1)))
return mid;
//否则最终结果一定在当前mid的右边,往右走
else
left = mid;
}
else
return mid;
}
return -1;
}
}
//正确,感觉有的时候不必纠结+1 -1的范围,实在不行就不+1 -1了,只不过多查俩数,和复杂度没太大关系,还能少动脑子。
第三次写
class Solution {
public int mySqrt(int x) {
//数组的话左闭右闭定义left=0,right=nums.length-1
//这现在是个数,把他当做一个数组的话,left=0,right=x 比如x=3,left=0相当于[0,1,2,3],left=0,right=nums.length-1(3)
int left = 0, right = x, mid = 0;
//特殊情况x=0的时候,直接返回0
if (x == 0)
return 0;
//特殊情况x=1的时候,直接返回1
if (x == 1)
return 1;
while (left <= right) {
mid = left + (right - left) / 2;
//要注意防止溢出,mid可能取到很大,用mid*mid和x判断,可能mid*mid大的离谱
if (mid > (x / mid))
right = mid- 1;
else if (mid < (x / mid)){
if ((mid + 1) > (x / (mid + 1)))
return mid;
else if ((mid + 1) == (x / (mid + 1)))
return mid + 1;
else
left = mid + 1;
}
else
return mid;
}
return -1;
}
}
//正确,其实还是要纠结+1 -1的范围,有些题就因为这个会TLE,怎么把数转换成数组上的左闭右开左闭右闭见第三次的注释
三、标准答案
1.方法一(二分法求)
public class Solution {
public int mySqrt(int x) {
// 特殊值判断
if (x == 0) {
return 0;
}
if (x == 1) {
return 1;
}
int left = 1;
int right = x / 2;
// 在区间 [left..right] 查找目标元素
while (left < right) {
int mid = left + (right - left + 1) / 2;
// 注意:这里为了避免乘法溢出,改用除法
if (mid > x / mid) {
// 下一轮搜索区间是 [left..mid - 1]
right = mid - 1;
} else {
// 下一轮搜索区间是 [mid..right]
left = mid;
}
}
return left;
}
}
2.方法二(牛顿迭代法)
class Solution {
int s;
public int mySqrt(int x) {
s=x;
if(x==0) return 0;
return ((int)(sqrts(x)));
}
public double sqrts(double x){
double res = (x + s / x) / 2;
if (res == x) {
return x;
} else {
return sqrts(res);
}
}
}
3.总结
无。