69.x的平方根

class Solution {
public:
    int mySqrt(int a) {
        // 1. 边界处理:0 的平方根还是 0
        if(a==0) return a;
        int l=1,r=a,mid,sqrt;
        // 2. 初始化指针
        // l (左指针) = 1,因为 a>0,答案至少是 1
        // r (右指针) = a,因为 a 的平方根不可能大于 a 本身(a>=1 时成立)
        // mid 用于存储中间值,sqrt 用于存储 a / mid 的结果
        while(l<=r){        // 3. 二分查找循环 (当左指针不超过右指针时)
            mid=l+(r-l)/2;            // 防止溢出的写法:相当于 (l + r) / 2
            sqrt=a/mid;
            if(sqrt==mid){
               return mid;
            }else if(mid>sqrt){
            // 情况2:mid > a/mid,说明 mid*mid > a,mid 太大了
            // 因此答案在左半边,移动右指针
                r=mid-1;
            }else{
            // 情况3:mid < a/mid,说明 mid*mid < a,mid 太小了
            // 因此答案在右半边,移动左指针
                l=mid+1;
            }
        }
        // 4. 循环结束(l > r),返回右指针 r
        // 此时 r 是最后一个满足 mid*mid <= a 的值,即向下取整的平方根
        return r;
    }
};
关键点 解释
为什么用 a / mid 而不是 mid * mid? 假设 a = 2147483647(最大 int),如果 mid 接近 46340, mid*mid不会爆;但如果 mid 大于 46340,mid*mid瞬间溢出变成负数,导致逻辑完全错误。用除法 a/mid,结果永远在 int 范围内,绝对安全。
为什么 sqrt == mid 时直接返回? 这代表 mid * mid == a,找到了精确的整数平方根。
为什么循环结束后返回 r 而不是 l? 二分结束条件是 l > r。在最后一次有效移动中,l 指向了第一个平方大于 a 的数,而 r 指向了最后一个平方小于等于 a 的数。题目要求向下取整,所以返回较小的那个,即 r。

时间复杂度:O(log⁡a)。每次循环将搜索区间缩小一半。
空间复杂度:O(1)。只使用了几个固定的整型变量,没有额外开辟内存。

方法二:牛顿迭代法

class Solution {
public:
    int mySqrt(int a) {
        long x=a;
        while(x*x>a){
            x=(x+a/x)/2;
        }
        return x;
    }
};
posted @ 2026-07-14 14:51  Acyclonepl  阅读(1)  评论(0)    收藏  举报