文章目录
69. x 的平方根
难度:简单
1. 题目描述
实现 int sqrt(int x)
函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2
示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
2. 解题思路
计算x
的平方根,这里暂不考虑各种求平方根的计算公式。
最简单的方法就是i
从0开始以步长1递增,当遇到第一个数i
,使得i * i > x
,那么i - 1
就是要找的数。当然这里有个问题,i * i
可能导致计算结果溢出变成死循环。正确的退出条件是当i > x / i
,这样变化后需要注意i
不能为0。
Java实现:
public int mySqrt(int x) {
if (x < 2) {
return 0;
}
int i = 1;
while (i <= x / i) {
i++;
}
return i - 1;
}
以上算法可以理解为在[1, x]
中找数i
,因为这里的[1, x]
已经按升序排好顺序,所以可以使用二分查找法减少查找次数。
这里比较麻烦的地方是如何调整查找区间和找到循环终止条件。和在排好序的数组中查找一个数的位置不同的是:这里要查找数x的平方根整数部分。刚开始把问题想的很复杂,比如:
- 当“中间值”不是要查找的对象时该如何确定下一个查找范围
- 应该在什么情况下退出查找
- 退出查找后,怎么确定是在刚刚好的位置(比如 4 -> 2),还是整数部分(8 -> 2)
实时证明这些考虑只是在给自己挖坑,在Mr__Kim的评论里说明了一种简单明了的解决办法,对于这个算法有如下优点:
- 兼容
x = 0
的情况 - 退出循环后不用考虑是在什么情况下退出的,因为程序实时的保存了解,只要程序退出了,当前保存的就是最终解
- 对于如何调整查找分区清晰明了
Java代码如下:
public int mySqrt(int x) {
int l = 1;
int r = x;
// 默认结果为0,如果x = 0,不会进入循环,直接退出
int ans = 0;
while (l <= r) {
int mid = l + (r - l) / 2;
// 要找的结果是真正平方根的向下取整值,
// 所以 mid <= x / mid 时,随着查找分区的调整,这个 mid 就无限逼近于最后要找的值
// 最后当退出循环时,这个 ans 就保存了最接近于真正的平方根的值,如 4 -> 2,8 -> 2
if (mid <= x / mid) {
// 实时保存最接近于平方根的结果
ans = mid;
// 由于当 mid == x / mid 时,已经将当前 mid 值保留了下来,所以下一次调整分区不必包含 mid
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
运行结果: