Sqrt(x)
Problem Description
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)in C++ orx ** 0.5in Python.
Examples
Example 1:Input: x = 4 Output: 2 Explanation: The square root of 4 is 2, so we return 2.
Input: x = 8 Output: 2 Explanation: The square root of 8 is 2.82842…, and since we round it down to the nearest integer, 2 is returned.
Constraints
0 <= x <= 2³¹ - 1
Halving the Square Roots Range
The square root of x must reside in the range [1, x].
We run binary search. Set left = 1 and right = x.
At each step, calculate the midpoint mid = left + (right - left) / 2.
Compare mid * mid with x:
- If
mid * mid == x, we have found the exact square root and returnmid. - If
mid * mid < x,midis a potential candidate for the rounded-down result, so we record it and search the right half:left = mid + 1. - If
mid * mid > x,midis too large, so we search the left half:right = mid - 1.
Solution 1: Binary Search with Squared Comparison
Perform binary search over the integers range up to x, checking products.
class Solution {
public int mySqrt(int x) {
if (x == 0) return 0;
int left = 1;
int right = x;
int ans = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
// Use division instead of multiplication to prevent integer overflow
if (mid <= x / mid) {
ans = mid; // record potential candidate
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
}class Solution:
def mySqrt(self, x: int) -> int:
if x == 0:
return 0
left = 1
right = x
ans = 0
while left <= right:
mid = left + (right - left) // 2
# Avoid overflow by using division or Python's native arbitrary precision
if mid <= x // mid:
ans = mid # record potential candidate
left = mid + 1
else:
right = mid - 1
return ansclass Solution {
public:
int mySqrt(int x) {
if (x == 0) return 0;
int left = 1;
int right = x;
int ans = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
if (mid <= x / mid) { // avoid integer overflow
ans = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
};Complexity Analysis
- Time Complexity: O(log x) since we halve the search range at each step.
- Space Complexity: O(1) auxiliary space as we use a fixed number of variables.
Where It Breaks
If x is extremely large and exceeds standard double-precision float ranges (though constrained by x <= 2^31 - 1 here), floating-point division is required.
Common Mistakes
- Integer Overflow: Using
mid * mid <= xdirectly in Java or C++. Ifmidis large,mid * midwill overflow 32-bit registers, yielding negative numbers. Usingmid <= x / midprevents this overflow. - Not handling zero: Forgetting to return 0 immediately when
x == 0, which can lead to a division by zero exception whenx / midexecutes atmid = 0.
Frequently Asked Questions
Why does mid <= x / mid prevent overflow?
Mathematically, mid <= x / mid is equivalent to mid * mid <= x. Since division does not grow the numeric size, it is safe from register overflow limits.
Can we use Newton’s method instead?
Yes. Newton’s method uses the update formula x_next = (x_curr + x / x_curr) / 2. It converges quadratically and is extremely fast, but binary search is simpler to implement.