LeetCode - 69. x 的平方根

题目

69. x 的平方根 - 力扣(LeetCode)

思路

初始化搜索范围:

  • 对于 x = 0,直接返回 0
  • 对于 x > 0,设置 left = 1, right = x

二分查找过程:

  • 当 left ≤ right 时循环:
  • 计算中点 mid = left + (right - left) / 2
  • 比较 mid 与 x/mid 的关系(等价于比较 mid^2 与 x,但避免溢出)
  • 如果 mid > x/mid:说明 mid 太大,更新 right = mid - 1
  • 如果 mid < x/mid:说明 mid 太小,更新 left = mid + 1
  • 如果 mid = x/mid:找到精确平方根,直接返回 mid

处理非完全平方数:

  • 循环结束后,right 是小于等于平方根的最大整数
  • 返回 right 作为结果

关键技巧

避免整数溢出:

  • 使用 mid > x/mid 代替 mid^2 > x
  • 这种比较方式数学上等价,但避免了中间结果溢出

边界处理:

  • 特殊处理 x = 0 的情况
  • 初始化 right = x 而不是 x-1,确保覆盖所有可能值

返回值选择:

  • 循环结束时 left > right
  • right 指向小于等于平方根的最大整数
  • left 指向大于平方根的最小整数

时间和空间复杂度

  • 时间复杂度:O(log x),二分查找的标准复杂度
  • 空间复杂度:O(1),只使用常数额外空间

读者的错误写法

cpp 复制代码
class Solution {
public:
    int mySqrt(int x) {
        int left = 0;
        int right = x-1;

        while(left <= right)
        {
            int mid = left + (right-left)/2;
            if(mid*mid > x)
            {
                right = mid-1;
            }
            else if(mid*mid < x)
            {
                left = mid+1;
            }
            else if(mid*mid == x)
            {
                return left;
            }
        }
        return left;
    }
};

初始化错误:

  • right = x-1 可能会导致问题。如果 x = 0,那么 right = -1,这是一个无效的索引。
  • 正确的初始化应该是 right = x,因为平方根不会超过 x 本身。

返回值错误:

  • 当找到 mid*mid == x 时,你返回的是 left 而不是 mid。
  • 应该返回 mid,因为 mid 是满足条件的值。

整数溢出风险:

  • 当 x 很大时,mid*mid 可能会导致整数溢出。
  • 应该使用 mid <= x/mid 进行比较,避免溢出。

循环结束后的返回值:

  • 循环结束后,你返回 left,但此时 left > right,left 指向的是第一个大于平方根的值。
  • 应该返回 right,因为 right 指向的是最后一个小于等于平方根的值。

正确写法

cpp 复制代码
class Solution {
public:
    int mySqrt(int x) {
        int left = 1;
        int right = x;

        while(left <= right)
        {
            int mid = left + (right-left)/2;
            if(mid > x/mid)
            {
                right = mid-1;
            }
            else if(mid < x/mid)
            {
                left = mid+1;
            }
            else if(mid == x/mid)
            {
                return mid;
            }
        }
        return right;
    }
};
相关推荐
智驱力人工智能1 分钟前
守护矿山动脉 矿山皮带跑偏AI识别系统的工程化实践与价值 皮带偏离检测 皮带状态异常检测 多模态皮带偏离监测系统
大数据·人工智能·opencv·算法·安全·yolo·边缘计算
没有bug.的程序员9 分钟前
Java内存模型(JMM)深度解析:从 volatile 到 happens-before 的底层机制
java·开发语言·并发编程·volatile·内存模型·jmm·happens-before
智驱力人工智能10 分钟前
构筑安全红线 发电站旋转设备停机合规监测的视觉分析技术与应用 旋转设备停机检测 旋转设备异常检测 设备停机AI行为建模
人工智能·opencv·算法·安全·目标检测·计算机视觉·边缘计算
雨中飘荡的记忆10 分钟前
Java注解校验实战
java
心丑姑娘14 分钟前
怎么理解ClickHouse的向量化执行
java·服务器·clickhouse
宵时待雨16 分钟前
数据结构(初阶)笔记归纳2:顺序表的实现
c语言·数据结构·笔记·算法
寻星探路16 分钟前
【算法进阶】滑动窗口与前缀和:从“和为 K”到“最小覆盖子串”的极限挑战
java·开发语言·c++·人工智能·python·算法·ai
不穿格子的程序员21 分钟前
从零开始刷算法——二叉树篇:层序遍历 + 有序数组转二叉搜索树
算法
阿蒙Amon22 分钟前
C#每日面试题-简述C#构造函数和析构函数
java·开发语言·c#
kaikaile199523 分钟前
同伦算法求解非线性方程组的MATLAB实现与优化
开发语言·算法·matlab