69. x 的平方根

难度:简单 | 主题:二分查找——单调性判断

题目

给你一个非负整数 x,计算并返回 x 的算术平方根。由于返回类型是整数,结果只保留整数部分,小数部分将被舍去。不允许使用任何内置指数函数和算符。

示例

 
输入:x = 8
 
输出:2
 
解释:8 的算术平方根是 2.82842...,返回整数部分 2
 

思路

先讲个故事:猜平方根

朋友说:“我想了一个数,它的平方不超过 100,你猜这个数最大是多少?”

你不会从 1 试到 10——你会猜 5,5² = 25 < 100;猜 8,8² = 64 < 100;猜 10,10² = 100,刚好。这就是二分查找平方根——在 [0, x] 中找最大的 m 使得 m² ≤ x。


引导式推导:从定义到二分

问题转化:求 sqrt(x) 的整数部分,等价于在 [0, x] 中找最后一个满足 mid * mid ≤ x 的数。

单调性:如果 mid * mid ≤ x,那么 mid 可能是答案,但更大的也可能满足,所以继续往右搜。


graph LR

    subgraph 在0到x中找ans

        A["猜ans=mid"] --> B{"mid² ≤ x ?"}

        B -->|Yes| C["可能小了<br/>left = mid+1"]

        B -->|No| D["太大了<br/>right = mid-1"]

    end

    C -->|循环结束| E["返回 right<br/>(最后一个合法值)"]

    D --> E

退出时为什么返回 right 不是 left? 循环退出时 left = right + 1。left² 一定 > x,right² 一定 ≤ x。right 就是最后一个合法答案。


可以优化搜索范围

x ≥ 4 时 sqrt(x) ≤ x // 2。所以搜索范围可以缩小到 [1, x // 2],减少一半。


graph LR

    A["x < 2"] -->|直接返回 x| B["0,1的平方根是自己"]

    A -->|x ≥ 2| C["搜索 [1, x//2]"]


代码

 
def mySqrt(self, x):
 
    if x < 2:
 
        return x
 
    left, right = 1, x // 2
 
    while left <= right:
 
        mid = left + (right - left) // 2
 
        if mid == x // mid:
 
            return mid
 
        elif mid < x // mid:
 
            left = mid + 1
 
        else:
 
            right = mid - 1
 
    return right
 

为什么用 mid == x // mid 代替 mid * mid == x 防止大数溢出。虽然 Python 不会溢出,但实践中写这个习惯在 C++/Java 实践中加分。


复杂度

指标解释
时间O(log x)二分范围 x
空间O(1)几个变量

实战考量

频率分析

出现在:一面二分基础题,考察对二分边界的理解以及溢出处理意识。

延伸思考

Q:为什么返回 right 不是 left?

A:退出时 left = right + 1。left² 一定 > x,right² 一定 ≤ x。right 是最后一个满足条件的值。

Q:用牛顿迭代法怎么写?

A:r = (r + x / r) / 2,迭代到 r² 与 x 的差小于精度。收敛速度比二分快。

Q:如果要求精确到小数点后 k 位呢?

A:把范围放大 10^(2k) 倍,最后再缩小回去。或用牛顿法浮点迭代。

易错点

  • 用除法防溢出

  • x < 2 的特殊处理

  • 返回 right 不是 left


生活类比

找平方根 → 找正方形边长

你知道一个正方形的面积是 10,想知道边长。你不会一个个平方算——二分猜边长:猜 3,面积 9 < 10;猜 4,面积 16 > 10。所以边长在 3~4 之间,整数部分是 3。


相关题目

题目关系
50Pow(x,n)快速幂
704二分查找二分基础

→ 返回题单:LeetCode学习路线图 > 八、二分查找

速记卡(面试闪卡)

Q1:一句话讲清「69. x 的平方根」到底是什么?

A:在 0 到 x 间二分,找平方不超过 x 的最大整数。

Q2:思路:二分找最后一个合法值 —— 怎么理解?

A:朋友让你猜平方不超过 100 的最大数:猜 5 太小、猜 10 刚好——这就是二分查找(Binary Search)。在 [0,x] 里不断夹逼,停在哪?落在右边界(Right Boundary)。

Q3:代码:除法防溢出 —— 怎么理解?

A:别用 mid*mid 怕溢出,改用 mid 与 x//mid 比大小,像用秤砣(Integer Division)比轻重;返回 right 不是 left,因为循环退出时 right 才是最后一个合法值。

Q4:复杂度:时间与空间 —— 怎么理解?

A:每次砍半,时间复杂度(Time Complexity)O(log x) 像折纸;只用了几个变量,空间复杂度(Space Complexity)O(1) 轻装上阵。

Q5:生活类比:猜正方形边长 —— 怎么理解?

A:已知面积 10 求边长,你不会挨个平方算——二分猜边长(Binary Search):猜 3 面积 9、猜 4 面积 16,整数部分是 3。平方求根(Square Root)就是这么接地气。

Q6:核心速记主线有哪些?

  • 二分找平方≤x最大数

  • 用除法防整数溢出

  • 返回 right 非 left

  • 时间 O(logx) 空间 O(1)

口诀

A:平方求根二分搜,

除法防溢记心头。

右界保留莫遗漏,

logx 时间不用愁。

相关链接