Skip to content

56. Sqrt(x)

๐Ÿ”— LeetCode Problem: 69. Sqrt(x)
๐Ÿ“Š Difficulty: Easy
๐Ÿท๏ธ Topics: Math, Binary Search

Problem Statement

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++ or x ** 0.5 in Python.

Example 1:

Input: x = 4
Output: 2
Explanation: The square root of 4 is 2, so we return 2.

Example 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^31 - 1


๐ŸŽจ Visual Understanding

The Problem Visualized

Find: floor(โˆšx)

x = 8

โˆš8 = 2.82842...
     โ†“ (round down)
Answer: 2

Visual representation:
0  1  2  3  4  5  6  7  8  9
         โ†‘
      Answer: 2

2ยฒ = 4 โ‰ค 8 โœ“
3ยฒ = 9 > 8  โœ—

So 2 is the largest integer whose square โ‰ค 8
x = 16

โˆš16 = 4.0 (exact)
Answer: 4

0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16
            โ†‘
         Answer: 4

4ยฒ = 16 โ‰ค 16 โœ“
5ยฒ = 25 > 16 โœ—

๐Ÿšจ CRITICAL INSIGHT - Why Binary Search Works

The Key Pattern!

We're searching for the largest integer k such that kยฒ โ‰ค x

Think of it as searching in this sequence:
  Numbers:  0  1  2  3  4  5  6  7  8  9  10
  Squares:  0  1  4  9  16 25 36 49 64 81 100

For x = 8:
  Which numbers have square โ‰ค 8?
  0ยฒ = 0  โ‰ค 8 โœ“
  1ยฒ = 1  โ‰ค 8 โœ“
  2ยฒ = 4  โ‰ค 8 โœ“
  3ยฒ = 9  > 8 โœ—
  4ยฒ = 16 > 8 โœ—
  ...

Pattern: [โœ“ โœ“ โœ“ | โœ— โœ— โœ— ...]
         [YYYYYYYY | NNNNNN ...]

We need the LAST โœ“ (largest valid)
= Find rightmost position where square โ‰ค x
= Binary Search on Answer Space!

Why This is Binary Search on Answer Space

Search Space:
  Not searching in an array
  Searching range [0, x] for answer

  Each "candidate" is a potential sqrt
  Each candidate has a property: square โ‰ค x or square > x

The Goal:
  Find LARGEST number whose square โ‰ค x
  = Find rightmost valid position
  = "Find Last/Upper Bound" pattern!

Key Insight:
  If kยฒ โ‰ค x, then answer is k or larger
  If kยฒ > x, then answer is smaller than k

  Can eliminate half at each step!

Example: x = 8, range [0, 8]

Check mid = 4:
  4ยฒ = 16 > 8
  Answer must be < 4
  Search [0, 3]

Check mid = 1:
  1ยฒ = 1 โ‰ค 8
  Answer could be 1 or larger
  Search [2, 3]

Check mid = 2:
  2ยฒ = 4 โ‰ค 8
  Answer could be 2 or larger
  Search [3, 3]

Check mid = 3:
  3ยฒ = 9 > 8
  Answer must be < 3
  Search ends

Best found: 2 โœ“

The Binary Search Invariant

Throughout the search:
  All numbers with square โ‰ค x are in [left, result]
  All numbers with square > x are in [result+1, right]

We track the best valid answer found so far:
  When midยฒ โ‰ค x: update result = mid, search right
  When midยฒ > x: search left

After loop: result = largest number whose square โ‰ค x

๐ŸŽฏ Approach 1: Linear Search (Brute Force)

The Most Natural Thinking ๐Ÿ’ญ

Core Logic:

Start from 0 and check each number:
  If iยฒ โ‰ค x and (i+1)ยฒ > x, then i is the answer

Or simply: find largest i where iยฒ โ‰ค x

Implementation

public int mySqrt(int x) {
    if (x < 2) return x;  // 0 and 1 are special cases

    // Check each number from 0 to x
    for (int i = 0; i <= x; i++) {
        long square = (long) i * i;  // Use long to avoid overflow

        // If current square exceeds x, previous was answer
        if (square > x) {
            return i - 1;
        }

        // If exact match
        if (square == x) {
            return i;
        }
    }

    return x;  // Should never reach here
}

โฐ Time: O(โˆšx) - Check up to โˆšx numbers
๐Ÿ’พ Space: O(1) - Only variables

Why This Works:

We increment i until iยฒ > x
Then i-1 is the largest number whose square โ‰ค x

โŒ Problem: Too slow for large x! If x = 2^31-1, checking billions of numbers!


๐ŸŽฏ Approach 2: Binary Search (Optimal) โญ

Better Approach ๐Ÿ’ก

๐Ÿง  The Core Insight

The answer is in range [0, x]
We're looking for: largest k where kยฒ โ‰ค x

This is MONOTONIC:
  If kยฒ โ‰ค x, then (k-1)ยฒ also โ‰ค x
  If kยฒ > x, then (k+1)ยฒ also > x

Pattern: [valid valid valid ... valid | invalid invalid ...]
         [YYYYYYYYYYYYYYYYYYYY | NNNNNNNNNNNNN]

Find the LAST valid (rightmost Y)
= Binary Search on Answer Space!

The Strategy:

Binary search on range [0, x]:
  If midยฒ โ‰ค x:
    mid is valid, might be answer
    But there might be larger valid number
    Track mid as potential answer
    Search right half

  If midยฒ > x:
    mid is too large
    Search left half

After loop: return best valid number found

Implementation

public int mySqrt(int x) {
    // Edge cases
    if (x < 2) return x;  // sqrt(0) = 0, sqrt(1) = 1

    int left = 0;
    int right = x;
    int result = 0;  // Track best valid answer

    while (left <= right) {
        // Safe mid calculation
        int mid = left + (right - left) / 2;

        // Use long to avoid overflow when calculating mid * mid
        long square = (long) mid * mid;

        if (square == x) {
            // Exact square root found
            return mid;
        }

        if (square < x) {
            // mid is valid, but there might be larger valid number
            result = mid;  // Track this as potential answer
            left = mid + 1;  // Search for larger
        } else {
            // mid is too large
            right = mid - 1;  // Search for smaller
        }
    }

    return result;  // Best valid answer found
}

โฐ Time: O(log x) - Binary search
๐Ÿ’พ Space: O(1) - Only variables

๐Ÿ” Dry Run

Example 1: x = 8

Goal: Find largest k where kยฒ โ‰ค 8

Initial: left = 0, right = 8, result = 0
         [0, 1, 2, 3, 4, 5, 6, 7, 8]
          โ†‘                       โ†‘
        left                    right

Iteration 1:
  mid = 0 + (8 - 0) / 2 = 4
  square = 4 ร— 4 = 16
  16 > 8, too large
  right = 3
  [0, 1, 2, 3, 4, 5, 6, 7, 8]
   โ†‘        โ†‘
  left    right

Iteration 2:
  mid = 0 + (3 - 0) / 2 = 1
  square = 1 ร— 1 = 1
  1 โ‰ค 8, valid!
  result = 1 (track it)
  left = 2
  [0, 1, 2, 3, 4, 5, 6, 7, 8]
         โ†‘  โ†‘
       left right

Iteration 3:
  mid = 2 + (3 - 2) / 2 = 2
  square = 2 ร— 2 = 4
  4 โ‰ค 8, valid!
  result = 2 (better answer)
  left = 3
  [0, 1, 2, 3, 4, 5, 6, 7, 8]
            โ†‘
         left/right

Iteration 4:
  mid = 3 + (3 - 3) / 2 = 3
  square = 3 ร— 3 = 9
  9 > 8, too large
  right = 2
  [0, 1, 2, 3, 4, 5, 6, 7, 8]
         โ†‘  โ†‘
      right left

Loop ends (left > right)
return result = 2 โœ“

Verification: 2ยฒ = 4 โ‰ค 8, 3ยฒ = 9 > 8 โœ“

Example 2: x = 4

Goal: Find largest k where kยฒ โ‰ค 4

Initial: left = 0, right = 4, result = 0
         [0, 1, 2, 3, 4]
          โ†‘           โ†‘
        left        right

Iteration 1:
  mid = 0 + (4 - 0) / 2 = 2
  square = 2 ร— 2 = 4
  4 == 4, exact match!
  return 2 โœ“

Verification: โˆš4 = 2 exactly โœ“

Example 3: x = 0

Edge case: x < 2
return x = 0 โœ“

Example 4: x = 1

Edge case: x < 2
return x = 1 โœ“

Example 5: x = 2147395599 (large number)

Initial: left = 0, right = 2147395599

After ~31 binary search iterations:
  Finds answer = 46339

Verification: 46339ยฒ = 2147395521 โ‰ค 2147395599 โœ“
              46340ยฒ = 2147488400 > 2147395599 โœ“

Without long cast:
  46340 ร— 46340 would overflow!
  That's why we use (long) mid * mid

๐ŸŽฏ Why This Works - Deep Dive

The Search Space:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Range: [0, x]
But can we optimize?

For x > 1, โˆšx < x/2
So we can search [0, x/2]... but x/2 still large

For safety and simplicity, search [0, x]
Binary search is fast enough!

The result Variable:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Why track result separately?
  When midยฒ โ‰ค x, mid is VALID
  But there might be LARGER valid number

  So we:
    1. Save mid as potential answer (result = mid)
    2. Keep searching right (left = mid + 1)

  If we find larger valid, we update result
  If all larger numbers are invalid, result has answer!

This is "Find Last Valid" pattern:
  Keep tracking best valid found
  Keep searching for better

Overflow Prevention:
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Critical: long square = (long) mid * mid

Why?
  mid can be up to x โ‰ˆ 2^31
  mid ร— mid can overflow int range

Example:
  mid = 46341
  mid ร— mid = 2,147,488,281
  As int: OVERFLOW (wraps to negative!)
  As long: Correct positive value โœ“

Always cast to long BEFORE multiplication!

Why Not Check mid > x/mid?
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Alternative to avoid overflow:
  Instead of: mid ร— mid > x
  Check: mid > x / mid

This works but:
  - Division is slower than multiplication
  - Needs special handling when mid = 0
  - Less clear code

Using long cast is cleaner and fast enough!

The "Find Last Valid" Pattern

This is the template for finding LAST/LARGEST valid:

1. Track result variable (best found so far)
2. When condition is TRUE:
   result = mid (track it)
   left = mid + 1 (search for better)
3. When condition is FALSE:
   right = mid - 1 (search smaller)
4. Return: result after loop

Applies to:
  - Find largest number with property
  - Find rightmost valid position
  - Find floor/maximum under constraint

Key insight:
  result preserves best answer found
  Continue searching for better

โš ๏ธ Common Mistakes to Avoid

Mistake 1: Not using long for square

// โŒ WRONG - Integer overflow
int square = mid * mid;
if (square > x) { ... }

// โœ“ CORRECT - Use long
long square = (long) mid * mid;
if (square > x) { ... }

Why it's critical:

For x = 2147395599, mid = 46341
mid * mid as int: OVERFLOW (negative number!)
Comparison breaks completely!

Cast to long BEFORE multiplication:
(long) mid * mid = correct positive value โœ“

Mistake 2: Not tracking result

// โŒ WRONG - Might return wrong answer
while (left <= right) {
    if (mid * mid <= x) {
        left = mid + 1;  // Lost the valid mid!
    }
}
return left;  // Wrong!

// โœ“ CORRECT - Track result
int result = 0;
while (left <= right) {
    if (square <= x) {
        result = mid;  // Save it!
        left = mid + 1;
    }
}
return result;  // Correct

Mistake 3: Wrong edge case handling

// โŒ WRONG - Fails for x = 0 or x = 1
int left = 1;  // Should be 0
int right = x;

// โœ“ CORRECT - Handle 0 and 1
if (x < 2) return x;
int left = 0;

Mistake 4: Using float/double

// โŒ WRONG - Problem says not to use pow or exponents
return (int) Math.sqrt(x);  // Not allowed!
return (int) Math.pow(x, 0.5);  // Not allowed!

// โœ“ CORRECT - Binary search
// (Our solution)

Mistake 5: Setting right = x for large x

// โš ๏ธ INEFFICIENT but works
int right = x;  // For x = 2^31, unnecessary large range

// โœ“ BETTER - Optimize right bound
int right = Math.min(x, 46341);  // โˆš(2^31) โ‰ˆ 46340

// But for simplicity, right = x is fine
// Binary search is fast anyway!

๐ŸŽฏ Pattern Recognition

Problem Type: Binary Search - Mathematical/On Answer Space
Core Pattern: Find Largest Value with Constraint

When to Apply:
โœ“ Mathematical computation without library
โœ“ Looking for LARGEST/MAXIMUM satisfying condition
โœ“ Monotonic property: if k works, all < k work
โœ“ Can check if value is valid
โœ“ Need O(log n) time

Recognition Keywords:
- "Square root"
- "Rounded down"
- "Must not use built-in"
- Find maximum/largest
- Mathematical constraint

Similar Problems:
- Valid Perfect Square (LC 367)
- Pow(x, n) (LC 50)
- Divide Two Integers (LC 29)
- Guess Number Higher or Lower (LC 374)
- First Bad Version (LC 278)

Key Difference from Other BS:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Find First/Minimum:                        โ”‚
โ”‚   - Search for smallest valid              โ”‚
โ”‚   - right = mid when valid                 โ”‚
โ”‚                                            โ”‚
โ”‚ Find Last/Maximum (This Problem):         โ”‚
โ”‚   - Search for largest valid               โ”‚
โ”‚   - result = mid when valid                โ”‚
โ”‚   - left = mid + 1 to find larger          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Track best answer and keep searching!

๐Ÿง  Interview Strategy

Step 1: "Need to find largest k where kยฒ โ‰ค x"
Step 2: "This is binary search on answer space [0, x]"
Step 3: "Pattern: [valid valid ... | invalid invalid ...]"
Step 4: "Track best valid, keep searching for larger"
Step 5: "Use long for overflow prevention"

Key Points to Mention:
- Binary search on RANGE, not array
- Looking for LARGEST valid number
- Track result as best valid found
- Continue searching for larger valid
- Cast to long prevents overflow
- Handle edge cases x < 2
- Time: O(log x), Space: O(1)
- Can't use Math.sqrt() or pow()

Why This Approach?
"I need to find the largest integer whose square is at most x.
This is perfect for binary search on the answer space [0, x].
The property is monotonic - if k is too large, all larger values
are also too large. I'll track the best valid answer found so far
and keep searching for a larger one. The critical detail is using
long when calculating mid squared to avoid integer overflow for
large values of x."

Overflow Handling:
"When mid is large, mid ร— mid can overflow integer range. For
example, 46341 squared is over 2 billion. So I cast to long
before multiplication to handle this safely."

๐Ÿ“ Quick Revision Notes

๐ŸŽฏ Core Concept:

Find Square Root (floor): Find largest k where kยฒ โ‰ค x using binary search on range [0, x]. Track best valid answer. When valid: save and search right. When invalid: search left. Critical: Use long for square calculation!

โšก Quick Implementation:

class Test {
  public int mySqrt(int x) {
    int left = 0; // since in question, 0 is also in range of inputs
    int right = x;
    int res = 0;

    while (left <= right) {
      int mid = left + (right - left) / 2;
      long product = (long) mid * mid;

      if(product == x) {
        return mid;
      } else if(product < x) {
        // mid is valid, but there might be larger valid number
        // hence could be a potential answer
        res = mid;
        left = mid + 1;
      } else {
        right = mid - 1;
      }
    }

    return res;
  }

  public static void main(String[] args) {
    Test t = new Test();
    for(int i = 0; i < 17; i++) {
      System.out.println("for i = "+i+": "+t.mySqrt(i));
    }    
  }
}

๐Ÿ”‘ Key Insights:

  • Pattern: Binary Search on Answer Space / Find Maximum
  • Goal: Largest k where kยฒ โ‰ค x
  • Monotonic: If kยฒ > x, then (k+1)ยฒ also > x
  • Track Result: Save best valid answer
  • Search Right: When valid, look for larger
  • Search Left: When invalid, look for smaller
  • Overflow: Use (long) mid * mid โ† CRITICAL!
  • Edge Cases: x < 2 handled separately
  • Loop: left <= right (standard BS)
  • Time: O(log x), Space: O(1)

๐ŸŽช Memory Aid:

"Find the LAST valid, track the BEST! Cast to LONG to avoid the test!"
Think: "Largest kยฒ โ‰ค x = Track best valid!"

๐Ÿ’ก The Key Insight:

When midยฒ โ‰ค x:
  result = mid (save it!)
  left = mid + 1 (find larger!)

When midยฒ > x:
  right = mid - 1 (too big!)

When midยฒ == x:
  return mid (exact!)

โš ๏ธ Critical Details:

1. Edge case: if (x < 2) return x
2. Overflow: long square = (long) mid * mid
3. Track: result = mid when valid
4. Search: left = mid + 1 when valid
5. Loop: while (left <= right)
6. Return: result (best valid found)

๐Ÿ”ฅ The Overflow Issue:

For large x near 2^31:
  mid can be ~46340
  mid ร— mid as int: OVERFLOW!
  mid ร— mid as long: Correct โœ“

Example:
  mid = 46341
  As int: mid * mid = negative (overflow!)
  As long: (long) mid * mid = 2,147,488,281 โœ“

Always: (long) mid * mid
Never: mid * mid

๐ŸŽฏ The Pattern - Find Last Valid:

Search space: [0, x]
Property: kยฒ โ‰ค x

[0, 1, 2, ..., k, k+1, ..., x]
[โœ“  โœ“  โœ“  ...  โœ“   โœ—  ...  โœ—]
                โ†‘
           Find this!

When โœ“: save it, search right (maybe larger โœ“)
When โœ—: search left (need smaller)

After loop: result = rightmost โœ“

๐Ÿ’ก Why Track Result:

Without tracking:
  Find valid mid = 2
  Search right for larger
  Find invalid mid = 3
  Search left
  Loop ends
  Lost the answer 2!

With tracking:
  Find valid mid = 2
  result = 2 (saved!)
  Search right
  Find invalid mid = 3
  Search left
  Loop ends
  Return result = 2 โœ“

๐Ÿงช Edge Cases

Case 1: x = 0

Input: 0
Output: 0
โˆš0 = 0

Case 2: x = 1

Input: 1
Output: 1
โˆš1 = 1

Case 3: Perfect square

Input: x = 16
Output: 4
โˆš16 = 4 exactly

Case 4: Not perfect square

Input: x = 8
Output: 2
โˆš8 โ‰ˆ 2.828, floor = 2

Case 5: Large number

Input: x = 2147395599
Output: 46339
Without long cast: OVERFLOW!
With long cast: Correct โœ“

Case 6: x = 2

Input: 2
Output: 1
โˆš2 โ‰ˆ 1.414, floor = 1

All handled correctly! โœ“


  • Valid Perfect Square (LC 367) - Similar but checks exact match
  • Pow(x, n) (LC 50) - Binary search for exponentiation
  • Divide Two Integers (LC 29) - Binary search for division
  • First Bad Version (LC 278) - Binary search on range

Happy practicing! ๐ŸŽฏ

Note: This is a classic "binary search on answer space" problem! The overflow prevention with long cast is the critical detail that many candidates miss!