Problem overview
The method perfectNumbers gets an array of integers nums and returns the perfect numbers among them, in the same order. A number is perfect when it equals the sum of its divisors that are smaller than itself. The number 6 is perfect, because 1 + 2 + 3 = 6. The number 1 is not perfect: it has no smaller divisors, so its sum is 0. A perfect number that appears twice is kept twice, and if no number is perfect the result is empty. Each number is between 1 and 10,000, and there are 1 to 20 of them.
For [6, 8, 28, 12] the answer is [6, 28]. The sum for 8 is 1 + 2 + 4 = 7, and for 12 it is 1 + 2 + 3 + 4 + 6 = 16, so neither matches. For [1, 5, 10] the sums are 0, 1 and 8, so the answer is empty. For [496, 6, 6] all three are perfect, so the answer is [496, 6, 6].
Approach: a helper for the divisor sum
The work is split in two. The helper sumOfDivisors takes one number n and returns the sum of the divisors of n that are smaller than n. perfectNumbers loops over the array and keeps each number that equals the helper's answer for it.
To find the divisors, try every d from 1 up to n - 1. A number d divides n evenly when the remainder n % d is 0. With numbers up to 10,000 and at most 20 of them, trying every d is fast enough, so no cleverness is needed.
Step by step
- In
sumOfDivisors, starttotalat 0. Forn = 1the loop never runs, so the sum stays 0. - Try every possible divisor:
for (let d = 1; d < n; d++). The conditiond < nleavesnitself out. - Add the divisors: if
n % d == 0, adddtototal. For 6, these are 1, 2 and 3. - Return
totalafter the loop. - In
perfectNumbers, start with an empty array namedperfect. - Loop over the numbers with
for (let num of nums). A perfect number that appears twice is visited twice, so it is kept twice. - Compare with the helper: if
this.sumOfDivisors(num) == num, pushnumontoperfect. - Return
perfectafter the loop.
The solution in JavaScript
class Solution {
sumOfDivisors(n) {
let total = 0;
for (let d = 1; d < n; d++) {
if (n % d == 0) {
total += d;
}
}
return total;
}
perfectNumbers(nums) {
let perfect = [];
for (let num of nums) {
if (this.sumOfDivisors(num) == num) {
perfect.push(num);
}
}
return perfect;
}
}
Some details:
- The remainder operator.
n % dis the remainder of the division. It is 0 exactly whenddividesn. - Calling the helper. Inside the class, use
this.sumOfDivisors(num). The call goes straight into the comparison, and the helper's own loop runs once for each number. - Whole numbers only. JavaScript numbers are doubles, but integers this small are exact, so
==between two sums is safe.
Following 12 and 28
For n = 12, the loop tries d from 1 to 11. The values 1, 2, 3, 4 and 6 leave a remainder of 0, so they are added: 1 + 2 + 3 + 4 + 6 = 16. Since 16 is not 12, the number 12 is not perfect, and it is skipped. Notice that the sum can be bigger than the number. For n = 28 the divisors found are 1, 2, 4, 7 and 14, and they add up to 28, so 28 is pushed onto perfect.
The numbers whose sum is smaller than the number are fine too. For 5 the only divisor is 1, and for 10 the divisors are 1, 2 and 5, giving 8. In both cases the sum is different from the number, so the answer for [1, 5, 10] stays empty.
Testing
The helper on single numbers returns these sums: 6 gives 6, 8 gives 7, 12 gives 16, 28 gives 28, 1 gives 0, 5 gives 1 and 10 gives 8. On the statement's examples the solution prints these lines, with an empty line for the second example:
6 28
496 6 6
The next perfect number after 496 is 8128, which is inside the limit of 10,000. The helper returns 8128 for it, so perfectNumbers([8128]) returns that one number.
Common mistakes
- Looping to
d <= n. That addsnitself, so the sum for 6 becomes 12 and no number is ever perfect. - Starting
dat 0. Dividing by zero givesNaNin JavaScript, not an error, andNaN == 0isfalse, so the answer would not change. It is still a wrong start: divisors begin at 1. - Treating 1 as perfect. Its sum is 0, which is not 1, and the rule handles it with no special case.
- Returning inside the loop. The method would stop after the first number.
- Removing duplicates. A perfect number that appears twice is kept twice, as in the third example.
