题目描述

:::fold-green 相关原题

LeetCode 原题: ✅ 69. x 的平方根

:::

给定非负实数 x 与允许的绝对误差 epsilon,不调用平方根库函数,返回一个与真实平方根之差不超过 epsilon 的近似值。

需要六位小数时,可取更小的内部误差后将结果格式化为六位小数。

示例 1:

输入: x = 2, epsilon = 0.000001
输出: 约 1.414214
解释: 1.414214 与真实平方根的差小于 10⁻⁶;允许输出其他满足误差的值。

示例 2:

输入: x = 0.25, epsilon = 0.000001
输出: 约 0.5
解释: x 小于 1 时,平方根可以大于 x,不能把右边界固定为 x。

提示:

  • 本实现使用 double:0≤x≤10¹²,10⁻⁹≤epsilon≤10⁻³。
  • 输出是近似实数,不是向下取整的整数。

题意分析

在非负区间上,平方随数值单调增加,因此可通过中点平方与 x 的比较排除一半候选。目标是根本身的绝对误差,应控制候选区间宽度,而不是仅判断平方后的差值。

解法:按区间宽度停止的实数二分

核心思路

[!blue]

初始化 [left,right] = [0,max(1,x)]:当 x >= 1 时平方根不超过 x,当 x < 1 时平方根可能大于 x,但不超过 1,因此该区间始终包含真根。

若 mid * mid > x,真根位于中点左侧,令 right = mid;否则令 left = mid。每次都保留真根所在半区,不使用整数二分中的 mid ± 1。

区间宽度不超过 epsilon 后返回中点,精确运算下误差至多为宽度的一半。题目给定的数值和误差范围也为浮点舍入留出了余量;格式化为固定小数位时会另有舍入误差,不能将显示精度与计算阈值混为一谈。

解题步骤

  1. 初始区间取 [0,max(1,x)],同时覆盖 x 小于 1 的情况。
  2. 比较中点平方与 x,保留包含平方根的半区。
  3. 区间宽度不超过 epsilon 时返回中点。

代码实现

class Solution {
    public double realSqrt(double x, double epsilon) {
        double left = 0;
        double right = Math.max(1, x);

        while (right - left > epsilon) {
            double mid = left + (right - left) / 2;

            if (mid * mid > x) {
                right = mid;
            } else {
                left = mid;
            }
        }

        return left + (right - left) / 2;
    }
}
func realSqrt(x, epsilon float64) float64 {
    left, right := 0.0, max(1.0, x)
    for right-left > epsilon {
        mid := left + (right-left)/2
        if mid*mid > x {
            right = mid
        } else {
            left = mid
        }
    }
    return left + (right-left)/2
}

复杂度分析

  • 时间复杂度:$O(\log (\max (1,x)/epsilon))$。
  • 空间复杂度:额外空间 $O(1)$。

关键点总结

[!green]

根始终在区间中,所以中点误差不超过区间宽度的一半;整数开方的下取整规则不适用于这里。

易错点总结

[!yellow]

epsilon 必须大于 0;不能把浮点近似误差与整数开方的截断规则混淆。六位小数格式化会引入至多约半个末位单位的舍入误差。

相似题目

题目 难度 关联与区别
69. x 的平方根 简单 同样二分平方根,原题求整数下界,本题以区间宽度控制浮点误差。
367. 有效的完全平方数 简单 同样比较平方与目标,原题要求精确整数相等,本题返回允许误差的近似值。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/2299490116
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!