Problem overview
The method MagicNumber takes an int, n, and keeps replacing it with the sum of its digits until only one digit is left. That final digit is the answer. For 39, the digit sum is 3 + 9 = 12, then 1 + 2 = 3, so the result is 3. For 928435, the first sum is 9 + 2 + 8 + 4 + 3 + 5 = 31 and the second is 3 + 1 = 4, so the result is 4.
Approach: split the work into two functions
The task combines two smaller jobs, and the lesson separates them:
- a helper
DigitSumthat adds up the digits of a number once; - the main method
MagicNumberthat calls the helper over and over until the number has a single digit.
Writing the main method first, as if the helper already existed, makes it short and easy to read. The loop always ends, because a number with two or more digits is larger than its digit sum. For example, 39 is larger than 12, so each round produces a smaller value.
Here is DigitSum(928435) in action. Each round adds the last digit to sum and then chops it off n:
n = 928435 sum = 0
n = 92843 sum = 5
n = 9284 sum = 8
n = 928 sum = 12
n = 92 sum = 20
n = 9 sum = 22
n = 0 sum = 31
When n reaches 0 the loop stops and 31 is returned. MagicNumber then repeats the process on 31 and gets 4.
The two loops have different conditions on purpose: the inner one stops at 0 because it needs every digit, while the outer one stops at a single digit, 9 or below.
Step by step
- Loop while there are two or more digits. A number has at least two digits exactly when it is greater than 9, so the loop is
while (n > 9). - Replace
nwith its digit sum.n = DigitSum(n);assigns the helper's result back. - Return
nafter the loop. Returning inside the loop would stop after the first round. - Declare the helper.
public int DigitSum(int n)takes anintand returns anint. It receives its own copy ofn, so changingninside it doesn't affect the caller's variable. - Start a running total.
int sum = 0;, because no digit has been added yet. - Loop while digits remain. A positive number still has a digit left, so
while (n > 0). - Add the last digit.
n % 10is the remainder after division by 10, which is the last digit, sosum += n % 10;. - Remove the last digit.
n /= 10;divides by 10. With twointoperands,/is integer division and drops the remainder, so928435becomes92843. - Return the sum after the loop, once every digit has been added.
The solution in C#
class Solution {
public int DigitSum(int n) {
int sum = 0;
while (n > 0) {
sum += n % 10;
n /= 10;
}
return sum;
}
public int MagicNumber(int n) {
while (n > 9) {
n = DigitSum(n);
}
return n;
}
}
The C# details behind it:
- Integer division truncates.
39 / 10is3, not3.9. That behaviour is what makesn /= 10remove the last digit. - Parameters are copies.
intarguments are passed by value, soDigitSumcan freely destroy itsnwhile counting. The original value stays with the caller. - Methods can call each other by their plain names when they belong to the same class. The order of the two methods in the file doesn't matter to the compiler.
- Compound assignment.
sum += xmeanssum = sum + x, andn /= 10meansn = n / 10.
Complexity
Time. One call to DigitSum takes one loop iteration per digit, which is O(log n), since the number of digits grows with the logarithm of the value. After the first call, the number is small: an int has at most 10 digits, so its digit sum is at most 90. The remaining rounds work on numbers of at most two digits, which makes them effectively constant. The total is O(log n).
Space: O(1). The code uses a few int variables.
Edge cases and common mistakes
- Already one digit.
7skips the loop and is returned as is. - Zero.
MagicNumber(0)returns0. The statement is about positive numbers, so this is only a safe fallback. - Negative input. The problem only uses positive numbers. A negative
nfails the testn > 9, so the method would return it unchanged. If negative values were possible, you would decide what the result should be and handle them before the loop. - The largest
int.2147483647sums to 46, then 10, then 1, so the result is1. The sum of digits never overflows. - Using
n >= 9in the first loop. It would sum the digits of 9 itself, which gives 9 again, and the loop would never end. - Using
/to get the last digit. The last digit comes from%. Division removes it. - Returning inside the loop. The method would stop after the first round, so
39would return12.
Testing
39gives3.928435gives4.7gives7.999gives9, sinceDigitSum(999)is27and then9.2147483647gives1.
As a side note, the same result has a closed form for positive n: 1 + (n - 1) % 9. The loop version is what the lesson asks for, and it is the one that shows how to take apart the digits of a number.