Leetcode 69. Sqrt(x)

We want to compute $\lfloor\sqrt{x}\rfloor$ for a non-negative integer $x$, without using any built-in function.

Naive Solution

class Solution {
    public int mySqrt(int x) {
        long ans = 1;
        while (ans * ans <= x) {
            ans++;
        }
        return (int) ans - 1;
    }
}

This solution is very straightforward and runs in $O(\sqrt{x})$, but we can do much better.

Binary Search

This is fundamentally a searching problem: we want the largest integer $m$ such that $m^2 \le x$. The search space is sorted, so we just need a lower and upper bound. But observe that for any $x > 1$:

\[\sqrt{x} < x/2 + 1\]

You can easily show this is true by squaring both sides:

\[\begin{aligned} x &< x^2/4 + x + 1 \\ 0 &< x^2/4 + 1 \quad\text{(subtract $x$; always true)} \end{aligned}\]

So we binary search over $[1,\, x/2 + 1]$. The runtime is $O(\log x)$.

class Solution {
    public int mySqrt(int x) {
        if (x < 2) return x;
        int l = 1;
        int r = x / 2 + 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            long square = (long) mid * mid; // cast to avoid overflow
            if (square == x) {
                return mid;
            } else if (square < x){
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        // after the loop
        // r is the largest value whose square is <= x
        // l is the smallest value whose square is > x
        return r;
    }
}

You might be surprised, but we can even do better.

Newton’s method

To compute $\sqrt{x}$, we want to solve the equation

\[y^2 = x.\]

This is equivalent to finding a root of the function

\[f(y) = y^2 - x.\]

Since $\sqrt{x}$ is the value of $y$ such that $f(y) = 0$, we can use Newton’s Method to approximate it.

Where Does Newton’s Update Formula Come From?

Newton’s method is based on the idea of approximating a function by its tangent line.

Suppose we want to find a root of a function

\[f(y) = 0.\]

Assume our current guess is $y_n$. Instead of working with the actual (possibly curved) function, we approximate it by its tangent line at $y_n$.

The equation of the tangent line is

\[L(y) = f(y_n) + f'(y_n)(y - y_n).\]

Since the tangent line approximates the function near $y_n$, we estimate the root by finding where this line crosses the x-axis.

Set

\[L(y_{n+1}) = 0.\]

Substituting,

\[f(y_n) + f'(y_n)(y_{n+1} - y_n) = 0.\]

Now solve for $y_{n+1}$:

\[\begin{aligned} f'(y_n)(y_{n+1} - y_n) &= -f(y_n), \\ y_{n+1} - y_n &= -\frac{f(y_n)}{f'(y_n)}, \\ y_{n+1} &= y_n - \frac{f(y_n)}{f'(y_n)}. \end{aligned}\]

This is Newton’s update formula:

\[\boxed{ y_{n+1} = y_n - \frac{f(y_n)}{f'(y_n)} }\]

For the square root problem,

\[f(y)=y^2-x, \qquad f'(y)=2y.\]

Substituting these into Newton’s formula gives

\[y_{n+1} = y_n - \frac{y_n^2-x}{2y_n}.\]

Simplifying,

\[\begin{aligned} y_{n+1} &= \frac{2y_n^2-(y_n^2-x)}{2y_n} \\ &= \frac{y_n^2+x}{2y_n} \\ &= \frac{1}{2}\left(y_n+\frac{x}{y_n}\right). \end{aligned}\]

Therefore, the iteration becomes

\[\boxed{ y_{n+1} = \frac{1}{2}\left(y_n + \frac{x}{y_n}\right) }\]

Intuition

Suppose our current guess is $y_n$.

  • If $y_n$ is too large, then $\frac{x}{y_n}$ is too small.
  • If $y_n$ is too small, then $\frac{x}{y_n}$ is too large.

The next guess is simply the average of these two values:

\[\frac{y_n + x/y_n}{2}.\]

This average moves the estimate much closer to the true square root.

Example

Find $\sqrt{10}$.

Start with the initial guess

\[y_0 = 10.\]

Then

\[y_1 = \frac{10 + 10/10}{2} = \frac{10 + 1}{2} = 5.5.\]

Next,

\[y_2 = \frac{5.5 + 10/5.5}{2} \approx 3.659.\]

Next,

\[y_3 \approx 3.196,\]

and

\[y_4 \approx 3.1623.\]

The true value is

\[\sqrt{10} \approx 3.16227766.\]

After only a few iterations, the approximation is already extremely accurate.

The code is even much simpler than the binary search solution:

class Solution {
    public int mySqrt(int x) {
        if (x < 2) return x;
        long r = x;
        while (r * r > x) {
            r = (r + x / r) / 2;
        }
        return (int) r;
    }
}

Runtime

If you want a Big-O in terms of the input value $x$, Newton’s method for square root is:

\[\boxed{O(\log\log x)}\]

iterations.

However, there is a subtle distinction:

Newton iteration

The update:

\[y_{n+1}=\frac{1}{2}\left(y_n+\frac{x}{y_n}\right)\]

has quadratic convergence: the error after one step is roughly the square of the previous error. That is why the number of correct bits doubles — it is not magic.

Let $a=\sqrt{x}$ and write the error as $e_n = y_n - a$. Substituting $y_n = a + e_n$ into the iteration and simplifying gives:

\[e_{n+1} = \frac{e_n^2}{2(a+e_n)}.\]

For small $e_n$, we have $a+e_n \approx a$, so:

\[|e_{n+1}| \approx \frac{|e_n|^2}{2a} = C|e_n|^2\]

for some constant $C$. That is quadratic convergence.

Bits of accuracy are just a logarithmic measure of error: $b$ correct bits means roughly

\[|e_n| \approx 2^{-b}.\]

Plug that in:

\[|e_{n+1}| \approx C(2^{-b})^2 = C\,2^{-2b} \approx 2^{-2b}.\]

Ignoring the constant $C$ (it only shifts things by a few bits), $2^{-2b}$ means we now have about $2b$ correct bits. So the bits roughly double each step.

Concretely, if you start with $b_0 = 5$ correct bits, Newton gives about $10$, then $20$, then $40$, then $80$. After $k$ iterations:

\[b_k \approx 2^k b_0.\]

To get $\lfloor\sqrt{x}\rfloor$ we need about $B = \log x$ bits, so $2^k b_0 \approx B$, which means:

\[k = O(\log\log x).\]

The chain is: quadratic convergence $\Rightarrow$ error is squared $\Rightarrow$ accurate bits double $\Rightarrow$ $O(\log\log x)$ iterations.


Why do some people say $O(1)$?

Because for a fixed integer type (like Java int):

\[x \le 2^{31}-1\]

The maximum input size is bounded. Newton takes at most around 20 iterations, so in practice:

\[O(20)=O(1)\]

for Java int.

But in algorithm analysis, where $x$ can grow arbitrarily large, the more meaningful answer is:

\[\boxed{O(\log\log x)}\]

For comparison:

  • Naive Solution:

    \[O(\sqrt{x})\]
  • Binary search:

    \[O(\log x)\]
  • Newton’s method: \(O(\log\log x)\) (and $O(1)$ for fixed-width int)

So Newton is asymptotically faster, but binary search is usually chosen in interviews because proving and implementing it is simpler.