Introduction

A perfect number is one of the oldest and most fascinating concepts in number theory. Although it dates back to ancient Greek mathematics, it continues to appear in modern Java coding interviews because it tests your understanding of loops, divisors, optimization techniques, and mathematical reasoning.

The simplest solution checks every possible divisor, but a more efficient approach uses the same square-root divisor-pair optimization commonly used when checking prime numbers. Learning this optimization not only improves your solution's performance but also demonstrates algorithmic thinking during interviews.

In this guide, you'll learn how perfect numbers work, implement both brute-force and optimized solutions in Java, print all perfect numbers within a range, understand the mathematical relationship between perfect numbers and prime numbers, and prepare for common interview questions.

Advertisement

What Is a Perfect Number?

A perfect number is a positive integer that is equal to the sum of all of its proper divisors.

Proper divisors are all positive divisors of a number except the number itself.

For example:

6

Its proper divisors are:

1, 2, 3

Their sum is:

1 + 2 + 3 = 6

Since the sum equals the original number, 6 is a perfect number.

Another example:

28

Proper divisors:

1, 2, 4, 7, 14

Their sum:

1 + 2 + 4 + 7 + 14 = 28

Therefore, 28 is also a perfect number.

The first few perfect numbers are:

6
28
496
8128
33550336

Notice how quickly they become rare.


Method 1: Brute Force (Check Every Divisor)

This is the simplest and most commonly taught solution.

Java Program

public class PerfectNumberBruteForce {

    public static void main(String[] args) {

        int num = 28;
        int sum = 0;

        for (int i = 1; i < num; i++) {

            if (num % i == 0) {
                sum += i;
            }
        }

        if (sum == num) {
            System.out.println(num + " is a perfect number.");
        } else {
            System.out.println(num + " is not a perfect number.");
        }
    }
}

Output

28 is a perfect number.

Step-by-Step Trace (num = 28)

i Is Divisor? Running Sum
1 Yes 1
2 Yes 3
3 No 3
4 Yes 7
5 No 7
6 No 7
7 Yes 14
8–13 No 14
14 Yes 28
15–27 No 28

Since:

sum = 28

the number is perfect.

Drawback

The loop checks almost every number before the input.

For very large numbers this becomes inefficient.


Method 2: Optimized Using Square Root

Divisors always occur in pairs.

For example, for 28:

1 × 28
2 × 14
4 × 7

Once you've checked up to the square root, every remaining divisor has already been discovered as the paired divisor.

Java Program

public class PerfectNumberOptimized {

    public static void main(String[] args) {

        int num = 28;

        if (num <= 1) {
            System.out.println(num + " is not a perfect number.");
            return;
        }

        int sum = 1;

        for (int i = 2; i * i <= num; i++) {

            if (num % i == 0) {

                sum += i;

                int pairedDivisor = num / i;

                if (pairedDivisor != i) {
                    sum += pairedDivisor;
                }
            }
        }

        if (sum == num) {
            System.out.println(num + " is a perfect number.");
        } else {
            System.out.println(num + " is not a perfect number.");
        }
    }
}

Output

28 is a perfect number.

Step-by-Step Trace

Start:

sum = 1

Loop:

i Divisible? Added Sum
2 Yes 2 and 14 17
3 No - 17
4 Yes 4 and 7 28
5 No - 28

Final result:

sum = 28

The optimization dramatically reduces the number of iterations.

Instead of checking:

1 → 27

it checks only:

2 → 5

Why Do We Check pairedDivisor != i?

Consider a perfect square like:

36

The divisor pair:

6 × 6

contains the same divisor twice.

Without this condition:

if (pairedDivisor != i)

you would incorrectly add 6 two times.


Method 3: Printing Perfect Numbers in a Range

Interviewers often extend the question by asking you to print every perfect number within a given range.

Java Program

public class PerfectNumbersInRange {

    static boolean isPerfect(int num) {

        if (num <= 1) {
            return false;
        }

        int sum = 1;

        for (int i = 2; i * i <= num; i++) {

            if (num % i == 0) {

                sum += i;

                int pair = num / i;

                if (pair != i) {
                    sum += pair;
                }
            }
        }

        return sum == num;
    }

    public static void main(String[] args) {

        int start = 1;
        int end = 10000;

        System.out.println("Perfect numbers:");

        for (int num = start; num <= end; num++) {

            if (isPerfect(num)) {
                System.out.print(num + " ");
            }
        }
    }
}

Output

Perfect numbers:
6 28 496 8128

Only four perfect numbers exist below 10,000.


Mathematical Pattern Behind Perfect Numbers

One of the most interesting facts about perfect numbers is their connection to prime numbers.

According to the Euclid-Euler Theorem:

If

2^p − 1

is a prime number (called a Mersenne Prime),

then

2^(p−1) × (2^p − 1)

is always a perfect number.

Example:

For:

p = 3

we get:

2³ − 1 = 7

Since 7 is prime,

2² × 7
= 4 × 7
= 28

which is a perfect number.

An interesting mathematical fact:

No odd perfect number has ever been discovered, and mathematicians still don't know whether one exists.

Mentioning this in an interview demonstrates deeper mathematical understanding.


How Java Handles This Internally

The following variables are primitive integers stored on the stack:

  • num

  • sum

  • i

  • pairedDivisor

The expression:

i * i <= num

uses only integer arithmetic.

Unlike:

Math.sqrt(num)

it avoids repeated floating-point calculations and is slightly more efficient.

No heap memory is allocated in either implementation because only primitive variables are used.


Real-Life Analogy

Imagine a company with multiple departments.

Each department contributes revenue.

If you add the contribution of every department except the company itself, and that total exactly equals the company's overall revenue, the business is perfectly balanced.

A perfect number behaves the same way.

All of its smaller contributing parts (its proper divisors) add up exactly to the whole.


Comparison Table

Method Time Complexity Best Used When
Brute Force O(n) Learning the basic concept
Square Root Optimization O(√n) Interviews and production code
Range-Based Search O(n√n) Finding all perfect numbers in a range

Best Practices

  • Use the square-root optimization whenever possible.

  • Initialize the sum with 1, since 1 is always a proper divisor for numbers greater than 1.

  • Use i * i <= num instead of repeatedly calling Math.sqrt().

  • Avoid double-counting divisor pairs.

  • Return false immediately for numbers less than or equal to 1.

  • Extract the logic into a reusable isPerfect() method.


Common Mistakes

Including the Number Itself

Incorrect:

1 + 2 + 3 + 6 = 12

Proper divisors exclude the number itself.

Correct:

1 + 2 + 3 = 6

Forgetting the Paired Divisor

When you find:

2

you should also add:

num / 2

Otherwise the divisor sum is incomplete.


Double Counting Perfect Squares

Always check:

pairedDivisor != i

before adding both divisors.


Forgetting Edge Cases

Numbers:

0
1
negative numbers

are never perfect numbers.


Confusing Perfect Numbers with Armstrong Numbers

Perfect numbers use:

sum of proper divisors

Armstrong numbers use:

sum of digit powers

These are completely different problems.


Expert Tips

A strong interview answer is:

"A perfect number equals the sum of its proper divisors. Instead of checking every possible divisor, I only check up to the square root because divisors always occur in pairs. Whenever I find one divisor, I also add its paired divisor, avoiding double-counting for perfect squares. This reduces the time complexity from O(n) to O(√n). Interestingly, every known even perfect number is generated from a Mersenne prime using the Euclid-Euler theorem."

Mentioning the Mersenne prime relationship often leaves a strong impression during interviews.


Pros and Cons

Method Advantages Disadvantages
Brute Force Very easy to understand Slow for large numbers
Square Root Optimization Fast and interview-friendly Slightly more complex divisor-pair logic

Frequently Asked Questions

What is a perfect number?

A positive integer equal to the sum of its proper divisors.

Example:

6 = 1 + 2 + 3

What are the first few perfect numbers?

6
28
496
8128
33550336

How can I check a perfect number efficiently?

Check divisors only up to the square root and add both members of every divisor pair.


What is the difference between a perfect number and an Armstrong number?

A perfect number depends on the sum of proper divisors.

An Armstrong number depends on the sum of digit powers.


Are there any odd perfect numbers?

None have ever been found.

Whether one exists remains an open mathematical problem.


What is the Euclid-Euler theorem?

It states that every even perfect number can be written as:

2^(p−1) × (2^p − 1)

where:

2^p − 1

is a Mersenne prime.


What is the time complexity of the optimized algorithm?

O(√n)

because only divisors up to the square root are checked.


Why should I avoid double-counting divisors?

Perfect squares have identical divisor pairs.

Without checking:

pairedDivisor != i

the divisor sum becomes incorrect.


Is 1 a perfect number?

No.

It has no proper divisors.


Why are perfect numbers so rare?

The gaps between perfect numbers grow rapidly, and they are closely tied to the extremely rare Mersenne primes.


Is this a common interview question?

Yes.

It is often used to test whether candidates know how to optimize divisor-based algorithms.


How do I print perfect numbers in a range?

Loop through the range and call a reusable isPerfect() method for each number.