LeetCode 69. x 的平方根
题目描述

题意分析
给定非负整数
x,返回它的算术平方根向下取整后的整数。也就是找到r,使得r² <= x < (r + 1)²;这里是舍去小数部分,不是四舍五入。
x不一定是完全平方数,不能只查找平方恰好等于x的数。x为0或1时答案就是自身;题目不允许直接使用开方函数或幂运算求结果。
解法:二分查找最大可行值
核心思路
[!blue]
非负整数越大,平方也越大。因此,满足
k² <= x的候选形成一个连续区间,答案就是这个区间的最右端:mid可行时,更小的数都可行;mid不可行时,更大的数也都不可行。每次都能排除一半候选,适合二分查找。先处理
x < 2,其余情况在[1, x / 2]中搜索。这个上界足够:若答案至少为2,就有k² >= 2k,再由k² <= x得到k <= x / 2;答案为1时也在区间内。
left、right表示还需检查的闭区间,ans保存已经确认的最大可行值。若mid² <= x,先记下mid,再令left = mid + 1,寻找更大的可行值;否则令right = mid - 1,排除mid以及更大的数。区间为空时,没有更大的可行候选,ans就是答案。比较平方时还要避免溢出。Java 先把
mid转成long再相乘;Go 判断mid <= x / mid,对正整数mid,它与mid² <= x等价。搜索下界为1,因此除法不会遇到零。
解题步骤
x < 2时直接返回x,处理平方根为零或一的边界。- 初始化
left = 1、right = x / 2、ans = 1,使用闭区间二分。- 只要
left <= right,取中点mid,安全判断其平方是否不超过x。- 可行时更新
ans = mid,并从mid + 1继续向右找;不可行时把右边界缩到mid - 1。- 搜索区间为空后返回
ans。
代码实现
class Solution {
public int mySqrt(int x) {
if (x < 2) {
return x;
}
int left = 1;
int right = x / 2;
int ans = 1;
while (left <= right) {
int mid = left + (right - left) / 2;
// 先提升类型再平方,避免比较之前已经溢出。
if ((long) mid * mid <= x) {
ans = mid;
// 当前值可行仍需向右找,目标是最大的可行整数。
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
}
func mySqrt(x int) int {
if x < 2 {
return x
}
left, right, ans := 1, x/2, 1
for left <= right {
mid := left + (right-left)/2
// 中点始终为正,用除法比较避免平方溢出。
if mid <= x/mid {
ans = mid
// 当前值可行仍需向右找,目标是最大的可行整数。
left = mid + 1
} else {
right = mid - 1
}
}
return ans
}
复杂度分析
- 时间复杂度:$O(\log x)$,
x >= 2时每轮将搜索区间缩小约一半;x < 2时为 $O(1)$。- 空间复杂度:$O(1)$,只保存边界、中点和当前答案。
关键点总结
[!green]
- 目标是满足平方不超过
x的最大整数,利用的是可行性的单调变化。ans保留已经找到的可行值,向右继续搜索负责确认它是否最大。- 搜索边界和乘法类型都要覆盖题目的整数范围。
易错点总结
[!yellow]
- 只在
mid² == x时返回,会漏掉不是完全平方数的输入;应寻找最后一个mid² <= x的值。- 找到任意可行值就返回,尚未确认右侧是否还有更大的答案。
- Java 写成
(long) (mid * mid)仍会先在int中溢出,必须在乘法前转换类型。- 使用除法判断时若允许
mid = 0,会发生除零;这里先处理小输入,再从1开始查找。- 退出时
left已经越过最大可行值,直接返回它会多一;代码返回保存下来的ans。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 367. 有效的完全平方数 | 简单 | 同样比较平方与目标,原题判断是否恰为完全平方,本题返回平方根的整数下界。 |
| 441. 排列硬币 | 简单 | 同样对单调增长的数值表达式二分,原题找满足三角数不超过n的最大层数。 |
| 34. 在排序数组中查找元素的第一个和最后一个位置 | 中等 | 在有序或具有单调判定的区间进行边界二分;本题以平方是否超过输入作为判定,该题定位等于目标值的左右边界。 |
| 35. 搜索插入位置 | 简单 | 在有序或具有单调判定的区间进行边界二分;本题以平方是否超过输入作为判定,该题寻找第一个不小于目标的位置。 |
| 补充题 149. 实数平方根的近似计算 | 中等 | 都在单调区间内二分平方根;补充题以误差阈值代替整数边界。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!