A two-pointer and number theory solution for checking whether an integer can be written as the sum of two square numbers.
Problem Restatement
We are given a non-negative integer c.
We need to determine whether there exist two integers a and b such that:
a * a + b * b == cIf such integers exist, return True.
Otherwise, return False.
Input and Output
| Item | Meaning |
|---|---|
| Input | A non-negative integer c |
| Output | True if c = a² + b² for some integers a and b, otherwise False |
Example function shape:
def judgeSquareSum(c: int) -> bool:
...Examples
Example 1:
c = 5We can choose:
a = 1
b = 2because:
1² + 2² = 1 + 4 = 5So the answer is:
TrueExample 2:
c = 3Possible squares are:
| Number | Square |
|---|---|
| 0 | 0 |
| 1 | 1 |
| 2 | 4 |
No pair sums to 3.
So the answer is:
FalseFirst Thought: Try Every Pair
A direct solution is:
- Try every possible
a. - Try every possible
b. - Check whether:
a * a + b * b == cThe largest useful value is:
sqrt(c)because larger squares already exceed c.
Code:
class Solution:
def judgeSquareSum(self, c: int) -> bool:
limit = int(c ** 0.5)
for a in range(limit + 1):
for b in range(limit + 1):
if a * a + b * b == c:
return True
return FalseThis works, but it takes:
O(c)time in the worst case.
We can do better.
Key Insight
Suppose we fix one number a.
Then we need:
b² = c - a²So after choosing a, we only need to know whether the remaining value is a perfect square.
Instead of checking every pair, we can use two pointers.
The smallest possible value is:
0The largest useful value is:
floor(sqrt(c))We maintain two pointers:
| Pointer | Meaning |
|---|---|
left | Smaller candidate |
right | Larger candidate |
Then compute:
left² + right²If the sum is too small, increase left.
If the sum is too large, decrease right.
This works because squares increase monotonically.
Algorithm
- Set:
left = 0
right = floor(sqrt(c))- While
left <= right:- Compute:
current = left² + right²If
current == c, returnTrue.If
current < c, increaseleft.If
current > c, decreaseright.If the loop finishes, return
False.
Implementation
class Solution:
def judgeSquareSum(self, c: int) -> bool:
left = 0
right = int(c ** 0.5)
while left <= right:
current = left * left + right * right
if current == c:
return True
if current < c:
left += 1
else:
right -= 1
return FalseCode Explanation
We start with the smallest and largest possible square roots:
left = 0
right = int(c ** 0.5)At each step:
current = left * left + right * rightIf the sum equals c, we found valid integers.
if current == c:
return TrueIf the sum is too small:
if current < c:
left += 1we increase the smaller square.
If the sum is too large:
else:
right -= 1we decrease the larger square.
Eventually the pointers cross:
left > rightAt that point, every possible pair has been checked.
Correctness
The algorithm maintains two integers left and right such that:
0 <= left <= right <= floor(sqrt(c))Every possible valid pair (a, b) must lie within this range, because if either value were larger than sqrt(c), its square alone would exceed c.
At each step, the algorithm computes:
left² + right²If this equals c, then the algorithm correctly returns True.
If the sum is smaller than c, then decreasing right would only make the sum smaller, because squares are non-decreasing. Therefore, the only possible way to reach c is to increase left.
If the sum is larger than c, then increasing left would only make the sum larger. Therefore, the only possible way to reach c is to decrease right.
Thus no valid pair is skipped.
The loop ends only after all feasible pairs have been eliminated. Therefore, if the algorithm returns False, no valid integers exist.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(sqrt(c)) | Each pointer moves at most sqrt(c) times |
| Space | O(1) | Only a few variables are stored |
Alternative Solution: Binary Search
Another approach is:
- Iterate over all possible
a. - Compute:
target = c - a²- Use binary search to check whether
targetis a perfect square.
class Solution:
def judgeSquareSum(self, c: int) -> bool:
limit = int(c ** 0.5)
for a in range(limit + 1):
target = c - a * a
left = 0
right = limit
while left <= right:
mid = (left + right) // 2
square = mid * mid
if square == target:
return True
if square < target:
left = mid + 1
else:
right = mid - 1
return FalseComplexity:
| Metric | Value |
|---|---|
| Time | O(sqrt(c) log c) |
| Space | O(1) |
The two-pointer solution is simpler and faster.
Number Theory Insight
There is also a famous theorem:
A non-negative integer c can be written as the sum of two squares if and only if every prime factor of the form:
4k + 3appears with an even exponent in the prime factorization of c.
Example:
5 = 1² + 2²Prime factorization:
5Since 5 is:
4k + 1it is allowed.
But:
3has factorization:
3and 3 is:
4k + 3with odd exponent 1, so it cannot be expressed as a sum of two squares.
This theorem gives another elegant mathematical solution.
Testing
def run_tests():
s = Solution()
assert s.judgeSquareSum(0) is True
assert s.judgeSquareSum(1) is True
assert s.judgeSquareSum(2) is True
assert s.judgeSquareSum(3) is False
assert s.judgeSquareSum(4) is True
assert s.judgeSquareSum(5) is True
assert s.judgeSquareSum(50) is True
assert s.judgeSquareSum(99999999) is False
print("all tests passed")
run_tests()Test meaning:
| Test | Why |
|---|---|
0 | 0² + 0² |
1 | 0² + 1² |
2 | 1² + 1² |
3 | Impossible case |
4 | 0² + 2² |
5 | Official example |
50 | 1² + 7² |
| Large value | Performance check |