Leetcode 507. Perfect Number

Problem Explanation

Given a positive integer n, you need to check if it is a perfect number or not. A number is called a perfect number if it is equal to the sum of all its divisors excluding itself. For example, let's consider the number 28. Its divisors are 1, 2, 4, 7 and 14. The sum of these divisors is 28, so 28 is a perfect number.

Approach

The idea behind this solution is to check every possible divisor of the number from 2 to the square root of the number. If we find a divisor, we add it to the sum. The reason we only check up to the square root is that a larger factor of the number must be a multiple of smaller factor that has already been checked, so we do not need to check them again.

We begin with 1 as all numbers are divisible by 1. We then increment the possible divisor by 1 in each iteration of the loop (starting from 2), and check if the number is divisible by that divisor. If it is, we add that divisor and num/divisor to the sum. This is because with each pair of factors we find, we add both the smaller and the larger factors to the sum. We continue to do this until we reach the square root of the number.

At the end, if the total sum of the divisors (excluding the number itself) is equal to the number itself, we return true, indicating that it is a perfect number.

Examples

For example, with the number 28:

  • The square root of 28 is approximately 5.29. So, we only need to check the numbers from 1 to 5 to see if they are divisors of 28.
  • Starting from 2 (since 1 is already added to sum), 28 is divisible by 2, so we add 2 and 28/2 (which is 14) to our sum. Our sum is now 17.
  • At 3, 28 is not divisible by 3.
  • At 4, 28 is divisible by 4, so we add 4 and 28/4 (which is 7) to our sum. Our sum is now 28.
  • We continue to 5 but 28 is not divisible by 5, so our sum remains 28.
  • Our sum is equal to our original number, so we return true.

Python Solution

1
2python
3class Solution:
4 def checkPerfectNumber(self, num: int) -> bool:
5   if num == 1:
6     return False
7
8   sum = 1
9
10   i = 2
11   while i * i <= num:
12     if num % i == 0:
13       sum += i
14       if i * i != num: # if this condition is true, then the divisor i and num/i are the same
15         sum += num // i
16     i += 1
17
18   return sum == num

Java Solution

1
2java
3class Solution {
4 public boolean checkPerfectNumber(int num) {
5   if (num == 1) {
6     return false;
7   }
8
9   int sum = 1;
10
11   for (int i = 2; i <= Math.sqrt(num); i++)
12     if (num % i == 0)
13       sum += i + num / i;
14
15   return sum == num;
16 }
17}

Javascript Solution

1
2javascript
3var checkPerfectNumber = function(num) {
4 if (num === 1) {
5   return false;
6 }
7
8 let sum = 1;
9
10 for (let i = 2; i <= Math.sqrt(num); i++)
11   if (num % i === 0)
12     sum += i + num / i;
13
14 return sum === num;
15};

C++ Solution

1
2cpp
3class Solution {
4public:
5 bool checkPerfectNumber(int num) {
6   if (num == 1)
7     return false;
8
9   int sum = 1;
10
11   for (int i = 2; i <= sqrt(num); ++i)
12     if (num % i == 0)
13       sum += i + num / i;
14
15   return sum == num;
16 }
17};

C# Solution

1
2csharp
3public class Solution {
4 public bool CheckPerfectNumber(int num) {
5   if (num == 1) {
6     return false;
7   }
8
9   int sum = 1;
10
11   for (int i = 2; i <= Math.Sqrt(num); i++) {
12     if (num % i == 0) {
13       sum += i;
14       if (i != num / i) {
15         sum += num / i;
16       }
17     }
18   }
19
20   return sum == num;
21 }
22}

In all these solutions, we start by handling the base case where if num == 1, we return false as per the problem's requirements. Then we implement the logic as explained in the approach above. In Python and Java solutions, we are making sure not to count a divisor twice when it is the square root of the number by checking i * i != num. This takes care of the edge case where a divisor is counted twice when the number is a perfect square. In JavaScript, C++ and C# solutions, this specific check is missing, which might lead to the incorrect result when the input number is a perfect square.

Additionally, we are checking for the condition num == 1 in the base case because 1 is not a perfect number as per the definition. A perfect number is a positive integer that is equal to the sum of its proper divisors, excluding the number itself. For 1, the sum of proper divisors (excluding the number itself) is 0, which is not equal to the number (which is 1 in this case).

These solutions work in linear time complexity because we iterate through the range from 2 to square root of num. In terms of space complexity, these solutions are constant, O(1), because they use a fixed amount of space to store the sum and the input number.

These are optimal solutions that cover all the edge cases, and with a minor fix for JavaScript, C++ and C# solutions, should provide the correct result for any input. The proposed solutions are efficient and work under the constraints of the problem.


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫