69. Sqrt(x) - Explanation
Description
You are given a non-negative integer x, return the square root of x rounded down to the nearest integer. The returned integer should be non-negative as well.
You must not use any built-in exponent function or operator.
- For example, do not use
pow(x, 0.5)inc++orx ** 0.5inpython.
Example 1:
Input: x = 9
Output: 3Example 2:
Input: x = 13
Output: 3Constraints:
0 <= x <= ((2^31)-1)
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Binary Search - Efficiently narrows down the search space by halving it each iteration
- Integer Overflow Handling - Squaring large numbers can overflow; use 64-bit types for intermediate calculations
- Bit Manipulation - Used in the recursive approach with right/left shifts to divide/multiply by powers of 2
- Newton's Method - An iterative numerical technique that converges quickly to the square root
1. Brute Force
Intuition
The square root of a number x is the largest integer i such that i * i <= x. We can find this by simply checking each integer starting from 1 until squaring it exceeds x. The answer is the last integer whose square did not exceed x.
Algorithm
- Handle the edge case where
xis0by returning0. - Initialize
resto1to track the potential answer. - Iterate from
1tox. For each integeri, check ifi * i > x. - If
i * i > x, return the previous valid resultres. - Otherwise, update
res = iand continue. - Return
resafter the loop.
Time & Space Complexity
- Time complexity:
- Space complexity:
2. In-Built Function
Intuition
Most programming languages provide a built-in square root function that computes the result efficiently using optimized mathematical algorithms (often Newton's method or similar). We can leverage this and simply truncate the result to get the integer floor of the square root.
Algorithm
- Call the language's built-in square root function on
x. - Convert the result to an integer (truncating any decimal part).
- Return the integer result.
Time & Space Complexity
- Time complexity:
- Space complexity:
3. Binary Search
Intuition
Since we are looking for the largest integer whose square is at most x, and the squares of integers are monotonically increasing, we can use binary search. The search space is [0, x], and we narrow it down by checking if the middle value squared is less than, greater than, or equal to x.
Algorithm
- Initialize
l = 0,r = x, andres = 0to store the answer. - While
l <= r:- Compute middle
m = l + (r - l) / 2. - If
m * m > x, the answer must be smaller, so setr = m - 1. - If
m * m < x,mis a valid candidate. Store it inresand search for a larger value by settingl = m + 1. - If
m * m == x, we found the exact square root, so returnm.
- Compute middle
- Return
resafter the loop.
Time & Space Complexity
- Time complexity:
- Space complexity:
4. Recursion
Intuition
We can exploit a mathematical property: sqrt(x) = 2 * sqrt(x / 4). By right-shifting x by 2 bits (dividing by 4), we recursively compute the square root of a smaller number. Then we left-shift the result by 1 (multiply by 2) to scale it back up. Finally, we check if incrementing by 1 still gives a valid square root.
Algorithm
- Base case: if
x < 2, returnx(sincesqrt(0) = 0andsqrt(1) = 1). - Recursively compute
l = mySqrt(x >> 2) << 1. This gets an approximate lower bound. - Compute
r = l + 1as the candidate one larger. - If
r * r > x, returnl. Otherwise, returnr.
Time & Space Complexity
- Time complexity:
- Space complexity: for recursion stack.
5. Newton's Method
Intuition
Newton's method is a numerical technique for finding roots of equations. To find sqrt(x), we solve r^2 = x, or equivalently find the root of f(r) = r^2 - x. Newton's iteration formula gives us r_new = (r + x/r) / 2. Starting with an initial guess of x, we repeatedly apply this formula until r^2 <= x, which converges quickly to the answer.
Algorithm
- Initialize
r = xas the starting guess. - While
r * r > x, updater = (r + x / r) / 2(using integer division, or right shift by 1). - The loop converges when
r^2 <= x. - Return
ras the integer square root.
Time & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Integer Overflow When Squaring
When computing m * m during binary search, the result can overflow if m is large (e.g., close to 46340 for 32-bit integers). Always cast to a 64-bit type before multiplication, such as (long)m * m in Java or (long long)m * m in C++, to prevent incorrect comparisons.
Off-by-One Errors in Binary Search
A subtle mistake is returning m when m * m < x instead of tracking it as a candidate and continuing to search for a larger valid value. The correct approach is to store m in a result variable when m * m <= x and keep searching, returning the stored result when the loop ends.
Sign in to join the discussion