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.




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • Leetcode 88. Merge Sorted Array
  • Leetcode 787. Cheapest Flights Within K Stops
  • Everything You Need to Know About Backpropagation
  • Sui Generis (ERC)
  • Linear Algebra Part 01: Identities