Skip to content
dsa450for five year olds

Searching & Sorting · 4 of 36

Square root of an integer

Find the biggest square of tiles you can build from a pile of x tiles, by guessing the side length higher or lower.

Simple way
time O(sqrt(x))
room O(1)
Clever way
time O(log x)
room O(1)

The problem, simply

You get a whole number x that is 0 or more. Return its square root rounded down: the biggest whole number r with r * r <= x. You may not use Math.sqrt or a power function.

For example the square root of 8 is about 2.83, so the answer is 2.

A story to remember it

Picture it

arrayside
012345678912345678910
arrayside x side
0123456789149162536496481100

Possible sides for x = 20, with the tiles each one needs. Sides up to 4 fit (16 tiles). From side 5 on, it needs more than 20.

  • done
  • answer
  • rejected

Examples

Not a perfect square

In
x = 8
Out
2

2 x 2 = 4 fits, 3 x 3 = 9 is too big.

A perfect square

In
x = 16
Out
4

4 x 4 is exactly 16.

Zero and one

In
x = 0, x = 1
Out
0, 1

Both are their own square roots. Handle them before the search.

The biggest int

In
x = 2147483647
Out
46340

46340 x 46340 = 2147395600 fits, 46341 x 46341 does not. Squaring a guess here overflows int, so use long.

Way 1: the simple way

Try sides 1, 2, 3, ... while the square still fits. The last side that fits is the answer.

java
class Solution {
    public int mySqrt(int x) {
        long r = 0;
        while ((r + 1) * (r + 1) <= x) r++;   // the next side still fits
        return (int) r;
    }
}

How long it takes: about sqrt(x) steps, O(sqrt(x)). For the biggest int that is 46340 steps, which is fine once, but slow if asked millions of times. Extra room: O(1).

Way 2: the clever way

Binary search the side.

  1. If x < 2, return x.
  2. The answer is between 1 and x / 2, because for x >= 4 the square root is at most half of x (and for 2 and 3 the answer is 1).
  3. Take mid. If mid * mid <= x, it fits: remember it and look for a bigger side (lo = mid + 1). Otherwise it is too big (hi = mid - 1).
  4. The last side that fit is the answer.

Higher or lower on the side length

01 / 10

arrayside
012345678912345678910hilo
arrayside x side
0123456789149162536496481100

x = 20. The side is somewhere from 1 to 20 / 2 = 10.

x
20
  • checking
  • done
  • answer
  • rejected
java
class Solution {
    public int mySqrt(int x) {
        if (x < 2) return x;
        long lo = 1, hi = x / 2, answer = 1;
        while (lo <= hi) {
            long mid = lo + (hi - lo) / 2;
            if (mid * mid <= x) {        // long math, so no overflow
                answer = mid;            // fits: try a bigger side
                lo = mid + 1;
            } else {
                hi = mid - 1;            // too many tiles: smaller side
            }
        }
        return (int) answer;
    }
}

How long it takes: the range halves each round, O(log x), about 31 rounds at most. Extra room: O(1).

Another way: Newton's method

Start with a guess r = x. Replace it by the average of r and x / r while r * r > x. If r is too big, x / r is too small, and their average is closer. The number of correct digits roughly doubles each round.

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

This is also O(log x) in the worst case, and much faster once it gets close. It is what calculators and libraries do, in spirit.

Watch out for

  • Returning lo or hi at the end without thinking. With this loop, hi ends as the answer too, but keeping answer is clearer.
  • hi = x / 2 is wrong for x = 1 (it gives 0). That is why x < 2 is handled first.
  • Using Math.sqrt and casting is often allowed in real code, but floating point can be off by one for huge long values. Fix with a small while check.

What interviewers ask next

  • Return the square root with 6 digits after the point. Binary search on doubles for about 60 rounds, or use Newton's method.
  • Is x a perfect square? Find the floor square root and check r * r == x.
  • The cube root, or the k-th root. Same search, with mid^k <= x, careful with overflow.
  • Why not search [0, x]? You can. It costs one extra round. x / 2 is just a tighter start.

Remember this

Grown-up words: the side length is the integer square root (floor of the square root), "higher or lower" is binary search on the answer, and averaging r with x / r is Newton's method.