LeetCode 258 - Add Digits
The problem asks us to repeatedly transform a number by summing its digits until only a single digit remains. The final single digit should then be returned. For example, if the input is 38, we first compute 3 + 8 = 11.
Difficulty: 🟢 Easy
Topics: Math, Simulation, Number Theory
Solution
Problem Understanding
The problem asks us to repeatedly transform a number by summing its digits until only a single digit remains. The final single digit should then be returned.
For example, if the input is 38, we first compute 3 + 8 = 11. Since 11 still has more than one digit, we repeat the process and compute 1 + 1 = 2. The result 2 is a single digit, so that becomes the answer.
The input is a non-negative integer num. The output is also an integer, specifically the final one-digit value obtained after repeatedly summing digits.
The constraint 0 <= num <= 2^31 - 1 tells us the input can be as large as a 32-bit signed integer. Even though this is not extremely large, the follow-up question strongly hints that there is a mathematical property that allows us to avoid simulation entirely and compute the result in constant time.
There are several important edge cases to consider:
- If
num = 0, the answer must remain0. This is special because the mathematical shortcut behaves slightly differently for zero. - If
numis already a single digit, the answer should simply be the number itself. - Large values such as
2147483647must still work correctly without overflow or excessive computation. - Numbers whose digit sum repeatedly collapses multiple times, such as
99999, should eventually converge correctly to a single digit.
Approaches
Brute Force Simulation
The most direct solution is to repeatedly compute the sum of the digits until the number becomes a single digit.
To compute the digit sum, we can repeatedly extract digits using modulo and integer division:
digit = num % 10num //= 10
We keep adding the extracted digits into a running total. Once all digits are processed, we replace the original number with the digit sum and repeat the process until the number is less than 10.
This approach is correct because it exactly follows the process described in the problem statement. Every iteration reduces the number toward a smaller value, eventually producing a single digit.
Although this solution is efficient enough for the given constraints, it still involves loops and repeated digit extraction. The follow-up specifically asks whether we can avoid loops and recursion entirely.
Optimal Mathematical Insight
The key observation is that repeatedly summing digits produces the number's digital root.
The digital root has a well-known mathematical property based on modulo 9:
- If a number is divisible by
9, its digital root is9 - Otherwise, the digital root is
num % 9 - The only exception is
0, whose digital root is0
This works because a number and the sum of its digits have the same remainder modulo 9.
For example:
38 % 9 = 23 + 8 = 111 + 1 = 2
Both produce the same final result.
Using this property, we can compute the answer in constant time with no loops or recursion.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(log n) | O(1) | Repeatedly sums digits until one digit remains |
| Optimal | O(1) | O(1) | Uses digital root mathematical property |
Algorithm Walkthrough
Optimal Algorithm
- Check whether the input number is
0.
This is necessary because the digital root formula behaves differently for zero. If we directly applied the modulo rule, we would incorrectly return 9 for 0.
2. Compute num % 9.
The remainder modulo 9 captures the same repeated digit-sum behavior as the simulation process.
3. If the remainder is 0, return 9.
Any positive multiple of 9 eventually reduces to 9. Examples include:
9 -> 918 -> 1 + 8 = 999 -> 9 + 9 = 18 -> 1 + 8 = 9
- Otherwise, return the remainder.
For all non-multiples of 9, the remainder itself is the final single-digit answer.
Why it works
The correctness comes from the modulo 9 property of decimal numbers. Every power of 10 is congruent to 1 modulo 9, which means a number and the sum of its digits always share the same remainder modulo 9.
For example:
$$38 = 3 \times 10 + 8$$
Since:
$$10 \equiv 1 \pmod{9}$$
We get:
$$38 \equiv 3 + 8 \pmod{9}$$
Repeating this process preserves the same modulo value until only one digit remains. That final digit is the digital root.
The central mathematical relationship is:
$\operatorname{digital_root}(n)=\begin{cases}0 & n=0 \ 9 & n\bmod 9=0 \text{ and } n>0 \ n\bmod 9 & \text{otherwise}\end{cases}$
Python Solution
class Solution:
def addDigits(self, num: int) -> int:
if num == 0:
return 0
remainder = num % 9
if remainder == 0:
return 9
return remainder
The implementation first handles the special case where the input is 0.
Next, it computes the remainder when dividing by 9. This remainder determines the digital root.
If the remainder is 0, the number must be a positive multiple of 9, so the answer is 9.
Otherwise, the remainder itself is returned.
This implementation directly follows the mathematical derivation and avoids any loops or recursion.
Go Solution
func addDigits(num int) int {
if num == 0 {
return 0
}
remainder := num % 9
if remainder == 0 {
return 9
}
return remainder
}
The Go implementation is almost identical to the Python version. Since the input constraint fits comfortably within Go's int type on LeetCode, no special overflow handling is required.
Go uses explicit variable declarations with :=, while Python relies on dynamic typing. Otherwise, the logic and edge case handling remain the same.
Worked Examples
Example 1
Input:
num = 38
Simulation process:
| Step | Current Number | Digit Sum |
|---|---|---|
| 1 | 38 | 3 + 8 = 11 |
| 2 | 11 | 1 + 1 = 2 |
Final answer:
2
Mathematical approach:
| Value | Result |
|---|---|
| 38 % 9 | 2 |
| Final Answer | 2 |
Example 2
Input:
num = 0
Since the number is already 0, we immediately return 0.
| Check | Result |
|---|---|
| num == 0 | true |
| Final Answer | 0 |
Additional Example
Input:
num = 99
Simulation:
| Step | Current Number | Digit Sum |
|---|---|---|
| 1 | 99 | 9 + 9 = 18 |
| 2 | 18 | 1 + 8 = 9 |
Mathematical approach:
| Value | Result |
|---|---|
| 99 % 9 | 0 |
| Positive multiple of 9 | yes |
| Final Answer | 9 |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(1) | Only a few arithmetic operations are performed |
| Space | O(1) | No additional memory proportional to input size is used |
The optimal solution performs a constant number of operations regardless of the input size. Unlike the brute-force simulation, there is no repeated digit extraction or iteration.
Test Cases
solution = Solution()
assert solution.addDigits(38) == 2 # Example case
assert solution.addDigits(0) == 0 # Zero edge case
assert solution.addDigits(5) == 5 # Single digit remains unchanged
assert solution.addDigits(9) == 9 # Single digit multiple of 9
assert solution.addDigits(18) == 9 # Multiple of 9
assert solution.addDigits(99) == 9 # Repeated reduction to 9
assert solution.addDigits(10) == 1 # Simple two-digit case
assert solution.addDigits(123) == 6 # Multiple digit reductions
assert solution.addDigits(99999) == 9 # Large repeated sums
assert solution.addDigits(2147483647) == 1 # Maximum 32-bit integer
| Test | Why |
|---|---|
38 |
Verifies the main example |
0 |
Confirms special-case handling |
5 |
Ensures single digits return unchanged |
9 |
Tests single-digit multiple of 9 |
18 |
Verifies modulo-9 behavior |
99 |
Tests repeated reductions |
10 |
Validates simple carry behavior |
123 |
Confirms standard digit summation |
99999 |
Stress test for repeated reductions |
2147483647 |
Confirms handling of maximum constraint value |
Edge Cases
Input Equal to Zero
The value 0 is the most important special case in this problem. If we blindly applied the modulo formula, we might incorrectly return 9 because 0 % 9 == 0.
The implementation explicitly checks:
if num == 0:
return 0
This guarantees correct behavior for zero.
Input Already a Single Digit
If the input is already between 1 and 9, the answer should simply be the number itself. For example:
5 -> 58 -> 8
The modulo formula naturally handles these cases because:
5 % 9 = 58 % 9 = 8
No additional logic is needed.
Positive Multiples of Nine
Numbers like 9, 18, 99, and 9999 are tricky because their modulo 9 result is 0, but their digital root should be 9, not 0.
For example:
18 -> 1 + 8 = 9
The implementation correctly handles this with:
if remainder == 0:
return 9
This ensures all positive multiples of 9 produce the correct result.