mySqrt 解题思路(二分查找)
题目
求非负整数 x 的整数平方根 (向下取整),即最大的整数 r 满足 r * r <= x。不能使用内置 sqrt。
例如:
-
x = 4→2 -
x = 8→2(因为2*2=4 <= 8,3*3=9 > 8) -
x = 0→0
核心思想:在 [0, x] 里二分找「最大的可行值」
平方根 r 一定在 [0, x] 范围内(x >= 1 时 r <= x)。这个区间是单调的:
-
若
mid * mid <= x,说明mid可行,答案至少是mid,往右找更大的 -
若
mid * mid > x,说明mid太大,答案在左边
于是可以用二分查找,不断缩小区间,直到锁定答案。
关键:判断条件从「比较大小」变成「比较平方」
普通二分是找 nums[mid] == target,这题的「条件」是:
text
mid * mid <= x → mid 是可行解,答案在 mid 或其右边
mid * mid > x → mid 太大,答案在 mid 左边
所以:
python
if mid * mid <= x:
left = mid + 1 # mid 可行,尝试更大的
else:
right = mid - 1 # mid 太大,往左缩
为什么循环结束后返回 right
用 while left <= right,循环结束时一定是 left = right + 1 (left 刚越过 right)。此时:
-
right是最后一个满足mid*mid <= x的位置 → 就是向下取整的平方根 ✅ -
left是第一个mid*mid > x的位置 → 是平方根 + 1
所以返回 right。
一句话:
right停在「可行区的右边界」,left停在「不可行区的左边界」,答案在right。
代码
python
class Solution:
def mySqrt(self, x: int) -> int:
left, right = 0, x
while left <= right:
mid = (left + right) // 2
if mid * mid <= x:
left = mid + 1 # mid 可行,往右找更大
else:
right = mid - 1 # mid 太大,往左缩
return right # 最大的可行值 = 平方根
执行流程演示
例 1:x = 8(答案 2)
text
left=0, right=8
mid=4: 16>8 → right=3
mid=1: 1<=8 → left=2
mid=2: 4<=8 → left=3
mid=3: 9>8 → right=2
left=3 > right=2 → 结束,return right=2 ✅
例 2:x = 4(答案 2)
text
left=0, right=4
mid=2: 4<=4 → left=3
mid=3: 9>4 → right=2
left=3 > right=2 → 结束,return right=2 ✅
例 3:x = 0(答案 0)
text
left=0, right=0
mid=0: 0<=0 → left=1
left=1 > right=0 → 结束,return right=0 ✅
例 4:x = 1(答案 1)
text
left=0, right=1
mid=0: 0<=1 → left=1
mid=1: 1<=1 → left=2
left=2 > right=1 → 结束,return right=1 ✅
边界与正确性
| 情况 | 处理 |
|---|---|
x = 0 |
right=0,返回 0 ✅ |
x = 1 |
返回 1 ✅ |
x 是完全平方数(4、9、16) |
返回精确平方根 ✅ |
x 不是完全平方数(8) |
返回向下取整 ✅ |
x 很大 |
mid*mid 在 Python 不会溢出(大整数),其他语言需防溢出 |
为什么 right = x 而不是 x - 1 :x=0 时 x-1=-1 会越界/跳过循环;x=1 时 x-1=0 也边界紧张。用 x 覆盖 [0, x] 最安全。
复杂度
-
时间 :
O(log x),每次区间减半 -
空间 :
O(1),只用几个变量
易错点
| 易错点 | 错误写法 | 正确 |
|---|---|---|
mid 公式 |
left + right // 2 |
(left + right) // 2 |
mid 位置 |
在循环外算一次 | 循环内每轮重算 |
| 循环条件 | while left < right |
while left <= right |
return 位置 |
写在循环里 | 循环外 |
| 返回值 | return left |
return right |
| 右边界 | right = x - 1 |
right = x |
| 比较 | mid > x |
mid * mid > x |
一句话记忆
在
[0, x]里二分,mid*mid <= x就往右找(left=mid+1),否则往左缩(right=mid-1);循环结束left=right+1,返回right即向下取整平方根。 判断条件是「平方比较」,不是「大小比较」。