1. 题目
实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。
Related Topics 数学 二分查找
👍 688 👎 0
2. 题解
2.1 解法1: 二分法
- 在 [0…x] 闭区间搜索该元素,
- 注意二分查找中几个关键点的写法:
- 注意 mid*mid 可能存在数值越界问题, 要将其转化为 long类型
- 注意初始条件 left=0, right=x
- while循环条件 (left<right) : 一般习惯不含等于
- mid 中点的选取, 若 mid = left + (right - left) / 2, 则为向下取整
- 边界收缩是 mid 还是 mid + 1, 若 mid 向下取整, 则 left的情况需要 mid+1, 向右需要加 1, 可以考虑只有两个元素的情况, 如果 left==mid, 则永远跳不出循环
- 循环结束落点的判断: 同样思考两个元素的情况, 如 x=8, 最后 left=2, right=3, 那么最后会落在 3 上, 所以返回结果需要减一
注意点:
- left , right 使用 long 类型 避免平方超界
- 相当于查找最后一个 mid 的平方 小于 x 的值, 所以向上取整, 使用 (right - left + 1) / 2 + left , 同时 == 的情况要分开讨论
class Solution {
public int mySqrt(int x) {
if (x == 0 || x == 1) return x;
long left = 0, right = x;
while (left < right) {
long mid = (right - left + 1) / 2 + left;
long temp = mid * mid;
if (temp == x) {
return (int)mid;
} else if (temp < x) {
left = mid;
} else {
right = mid - 1;
}
}
return (int)left;
}
}
写法2:
class Solution {
public int mySqrt(int x) {
if (x == 0 || x == 1) {
return x;
}
int left = 0, right = x;
while (left < right) {
// 这里是向下取整
int mid = left + (right - left) / 2;
long temp = (long) mid * mid;
if (temp == x) {
return mid;
} else if (temp < x) {
// 因为mid 计算时向下取整, 所以左边界需要加 1, 可以考虑只有两个元素的情况, 如果 left==mid, 则永远跳不出循环
left = mid + 1;
} else {
right = mid;
}
}
// 最后需要考虑落在的元素是否是答案, 可能会相差1
return left - 1;
}
}
参考: 二分查找(Java)
2.2 解法2: 牛顿迭代法
- 每次根据导数公式计算结果 t, 若 t*t-x < 1, 误差小于1, 即可返回结果
设结果为 ans, ans=(ans + C / ans ) /2, 其中 C 为任意数, 一般取 x
拓展: 若要求精确到0.001, 类似这种, 只需将 1 改成相应的精度即可
注意:
1.循环的条件 为 >=, 就继续循环
2.记住公式 t=(t+x/t)/2
class Solution {
public int mySqrt(int x) {
if (x == 0 || x == 1) {
return x;
}
double t = x;
while (t * t - x >= 1) {
t = (t + x / t) / 2;
}
return (int)t;
}
}