LeetCode 1952 - Three Divisors
The problem asks us to determine whether a given integer n has exactly three positive divisors. In other words, we want to check if there are precisely three distinct integers d such that n % d == 0 and d 0.
Difficulty: 🟢 Easy
Topics: Math, Enumeration, Number Theory
Solution
Problem Understanding
The problem asks us to determine whether a given integer n has exactly three positive divisors. In other words, we want to check if there are precisely three distinct integers d such that n % d == 0 and d > 0. For example, the number 4 has divisors 1, 2, and 4, which satisfies the condition, while 2 only has divisors 1 and 2, which does not.
The input is a single integer n constrained by 1 <= n <= 10^4, so it is relatively small. The output is a boolean value: true if n has exactly three divisors, false otherwise.
Key insights include realizing that a number with exactly three positive divisors must have the form p^2, where p is a prime number. This is because divisors of p^2 are 1, p, and p^2. If n is not a perfect square or its square root is not prime, then n cannot have exactly three divisors.
Important edge cases include n = 1, which only has one divisor, and perfect squares of composite numbers, such as n = 9 (3^2) or n = 16 (4^2). Only perfect squares of primes will satisfy the condition.
Approaches
A brute-force approach would enumerate all numbers from 1 to n and count how many divide n evenly. If the count reaches exactly three, we return true; otherwise, we return false. While this approach is simple and correct, it is inefficient for larger values of n because it checks divisibility for every integer up to n.
The key insight to an optimal solution is the property that any number with exactly three divisors must be the square of a prime. Therefore, the solution reduces to two checks: first, whether n is a perfect square, and second, whether its square root is prime. This is much faster because we only need to compute the integer square root and perform a primality check.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(1) | Check each integer from 1 to n for divisibility and count divisors |
| Optimal | O(√n) | O(1) | Check if n is a perfect square and verify if the square root is prime |
Algorithm Walkthrough
- Compute the integer square root of
nusing a built-in square root function or integer exponentiation. This gives us a candidatesqrt_nsuch thatsqrt_n * sqrt_n == nifnis a perfect square. - If
nis not a perfect square (i.e.,sqrt_n * sqrt_n != n), returnfalseimmediately, since a number with exactly three divisors must be a perfect square. - If
nis a perfect square, we now need to check ifsqrt_nis prime. A number is prime if it is greater than 1 and divisible only by 1 and itself. - To check primality efficiently, iterate from 2 up to the square root of
sqrt_n. If any number dividessqrt_n, it is not prime, and we returnfalse. - If no divisors are found in the loop,
sqrt_nis prime, and thusnhas exactly three divisors. Returntrue.
Why it works: The key invariant is that the only numbers with exactly three positive divisors are perfect squares of prime numbers. This is because divisors of p^2 are limited to 1, p, and p^2. Any other structure either produces fewer or more than three divisors.
Python Solution
import math
class Solution:
def isThree(self, n: int) -> bool:
sqrt_n = int(math.isqrt(n))
if sqrt_n * sqrt_n != n:
return False
if sqrt_n < 2:
return False
for i in range(2, int(math.isqrt(sqrt_n)) + 1):
if sqrt_n % i == 0:
return False
return True
The code first computes the integer square root of n to check for perfect-square status. If n is not a perfect square, the function immediately returns false. Next, it ensures that the square root is greater than 1, as 1 is not prime. Then, it iterates up to the square root of sqrt_n to check for divisibility. If any factor is found, sqrt_n is not prime, so n cannot have exactly three divisors. If no factors are found, the function returns true.
Go Solution
import "math"
func isThree(n int) bool {
sqrtN := int(math.Sqrt(float64(n)))
if sqrtN*sqrtN != n {
return false
}
if sqrtN < 2 {
return false
}
for i := 2; i*i <= sqrtN; i++ {
if sqrtN % i == 0 {
return false
}
}
return true
}
In Go, math.Sqrt returns a float64, so we cast it to an integer. The integer square root check ensures that n is a perfect square. The loop checks for primality by testing divisors up to the integer square root of sqrtN. Otherwise, the logic mirrors the Python solution.
Worked Examples
Example 1: n = 2
- Compute
sqrt_n = int(sqrt(2)) = 1. - Check
sqrt_n * sqrt_n == n:1*1 != 2, so returnfalse.
Example 2: n = 4
- Compute
sqrt_n = int(sqrt(4)) = 2. - Check
sqrt_n * sqrt_n == n:2*2 == 4, proceed. - Check if
sqrt_nis prime.2is prime, so returntrue.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(√n) | We compute the square root and check for divisibility up to √(sqrt(n)) for primality |
| Space | O(1) | Only constant extra variables are used |
The optimal solution reduces the problem size dramatically compared to brute-force by leveraging number theory properties, so even the worst-case check is efficient for n <= 10^4.
Test Cases
# Provided examples
assert Solution().isThree(2) == False # 2 has only two divisors
assert Solution().isThree(4) == True # 4 = 2^2, prime square
# Boundary values
assert Solution().isThree(1) == False # 1 has only one divisor
assert Solution().isThree(9) == True # 9 = 3^2, prime square
assert Solution().isThree(16) == False # 16 = 4^2, 4 is not prime
# Larger primes and non-primes
assert Solution().isThree(49) == True # 7^2, 7 is prime
assert Solution().isThree(100) == False # 10^2, 10 is not prime
| Test | Why |
|---|---|
n = 2 |
Smallest prime number, only two divisors |
n = 4 |
Smallest perfect square of a prime |
n = 1 |
Edge case, only one divisor |
n = 9 |
Perfect square of prime 3 |
n = 16 |
Perfect square of non-prime 4 |
n = 49 |
Larger prime square 7^2 |
n = 100 |
Perfect square of composite 10 |
Edge Cases
The first important edge case is n = 1. Since 1 only has a single divisor, any naive approach that counts divisors may incorrectly assume it has three divisors. The implementation explicitly handles n = 1 by checking the square root and prime conditions.
The second edge case is perfect squares of non-primes, such as n = 16 (4^2). A naive check for perfect squares would return true incorrectly if we do not validate that the square root is prime. Our algorithm handles this by performing a prime check on the square root.
The third edge case is large prime squares near the upper limit, such as n = 10_000. We need to ensure that the integer square root calculation and primality check are efficient. The algorithm only iterates up to √(sqrt(n)), which is small even for the maximum input, making it robust against performance issues.