The Balanced Sum

An easy Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.

Domain
Python
Difficulty
easy
Seniority
L3
Asked in
Citadel

Problem

A reviewer auditing a number-theory quiz bank flags an integer as perfect when it equals the sum of all its positive divisors smaller than itself. Given a positive integer n, report whether it qualifies.

Some numbers have a rare quality that mathematicians revere.

Example 1

Input:

n = 28

Output:

true

Example 2

Input:

n = 12

Output:

false

Worked solution and explanation

This is a divisor-sum check dressed up as a quiz-bank audit, and the only line that separates candidates is the first one. Everyone writes the loop. The tell is the seed: start divisor_sum at 1 because 'every number is divisible by 1' and you have quietly assumed n > 1. Feed it n = 1 and the seed alone equals n, so the function calls 1 perfect. The guard that rejects n <= 1 before seeding is the difference between a pass and a confident wrong answer on the smallest input there is.

Getting there

Step 1: Settle the tiny input first

1 has no divisor below itself, so its total is 0 and the answer is False. Return early for n <= 1. After that guard, 1 is a genuine smaller divisor of every remaining n, and seeding the sum with it is safe.

Step 2: Walk candidates only up to the square root

Divisors come in pairs: if candidate divides n, so does n // candidate, and one of the two is never above the square root. Testing while candidate * candidate <= n finds every pair in about sqrt(n) checks instead of n.

Step 3: Count a square's root once

When partner == candidate the pair collapses to a single divisor. Adding it twice inflates the total on inputs like 36, which is harmless there but wrong in principle, and interviewers ask about it.

Step 4: Compare the total to n

Starting the walk at 2 keeps n out of the sum by construction: its partner is 1, which the seed already covers. Equality with n is the whole answer.

Guard, seed, pair up to the square root
def is_perfect_number(n):
    if n <= 1:
        return False

    # 1 divides every n above 1; starting at 2 keeps n itself out of the sum
    divisor_sum = 1
    candidate = 2
    while candidate * candidate <= n:
        if n % candidate == 0:
            partner = n // candidate
            divisor_sum += candidate
            if partner != candidate:
                divisor_sum += partner
        candidate += 1

    return divisor_sum == n
Seed, then loop
divisor_sum = 1 with no guard is correct for every n above 1, but n = 1 returns True because the seed already matches it.
Guard, then seed
if n <= 1: return False runs first, so the seed of 1 is always a real divisor below n by the time it is added.

Common follow-up questions