Problem overview
This lesson has two functions. The helper digit_sum receives a whole number n and returns the sum of its digits: for 472 that is 4 + 7 + 2 = 13. The function that is tested, biggest_digit_sum, receives a vector nums and returns the number whose digits add up to the most. If two numbers have the same digit sum, the one that comes first wins. It returns the number itself, not its digit sum.
For [472, 95, 1000] the digit sums are 13, 14 and 1, so the answer is 95. For [19, 55, 28] all three sums are 10, so the first number, 19, wins the tie. For [0, 7] the sums are 0 and 7, so the answer is 7. Every number is between 0 and 1,000,000,000, and the vector has at least one number.
Approach
Split the task. The helper takes digits off a number one at a time: the remainder after dividing by 10 is the last digit, and dividing by 10 drops it. Repeat until nothing is left. Then biggest_digit_sum is the usual "running best": keep the winner so far and replace it only when a number has a strictly bigger digit sum.
Step by step
- In
digit_sum, function parameters are immutable in Rust, so the loop can't changen. Declare a mutable copy:let mut num = n;. - Declare
let mut total = 0;. Forn = 0the loop never runs and 0 is the right answer. - Loop
while num > 0. Each turn removes one digit, sonumreaches 0 when all digits are gone. - Inside, add
num % 10(the last digit;472 % 10is 2) tototal. - Still inside, set
num = num / 10. Integer division drops the remainder, so 472 becomes 47. Without this line the loop never ends. - After the loop, return
total. - In
biggest_digit_sum, startbestatnums[0], the first number. - Loop over
&nums. IfSelf::digit_sum(*num) > Self::digit_sum(best), setbest = *num. - Return
best.
The solution in Rust
impl Solution {
fn digit_sum(n: i32) -> i32 {
let mut num = n;
let mut total = 0;
while num > 0 {
total += num % 10;
num = num / 10;
}
return total;
}
fn biggest_digit_sum(nums: Vec<i32>) -> i32 {
let mut best = nums[0];
for num in &nums {
if Self::digit_sum(*num) > Self::digit_sum(best) {
best = *num;
}
}
return best;
}
}
Rust details
- Mutability. A variable declared with plain
letcan't be changed, and neither can a parameter. Writinglet total = 0;and thentotal += ..., or assigning tondirectly, gives the compiler errorscannot assign twice to immutable variable `total`andcannot assign to immutable argument `n`. That is why the solution copiesnintolet mut numand useslet mut total. - Division. Both operands are
i32, so/drops the remainder:472 / 10is 47, and7 / 10is 0. - Ties. The comparison uses
>, not>=. On a tie,bestis not replaced, so the number that came first keeps the place. - The first number compares with itself. The loop starts at the first number again. That comparison is never "greater", so it does no harm.
Watching the loops work
Inside the helper, the digits of 472 come off from the right:
num=472 digit=2 total=2
num=47 digit=7 total=9
num=4 digit=4 total=13
After the third turn num is 0, the loop stops and 13 is returned. In biggest_digit_sum, best changes only when a strictly bigger digit sum shows up:
[472, 95, 1000]
num=472 sum=13 best=472
num=95 sum=14 best=95
num=1000 sum=1 best=95
[19, 55, 28]
num=19 sum=10 best=19
num=55 sum=10 best=19
num=28 sum=10 best=19
In the second vector every sum is 10, nothing is strictly bigger than the first, and 19 stays the winner.
Why the helper is separate
The comparison digit_sum(*num) > digit_sum(best) reads almost like the task itself. All the digit-taking work stays inside the helper, so the loop in biggest_digit_sum only has to compare. Note that the helper is called twice per number, once for the candidate and once for the current best. That is a little wasteful, but with small inputs it costs nothing, and it keeps the code short. Storing the best sum in its own variable would avoid the repeat call.
Trying it
biggest_digit_sum([472, 95, 1000]) -> 95
biggest_digit_sum([19, 55, 28]) -> 19
biggest_digit_sum([0, 7]) -> 7
digit_sum(472), digit_sum(0), digit_sum(1000000000), digit_sum(999999999) -> 13, 0, 1, 81
The largest allowed value, 1,000,000,000, fits in an i32 and has a digit sum of 1. A nine-digit number made of 9s has the biggest possible sum here, 81. So the sums are always small, and total can't overflow.
A variant that calls the helper once per number
If you want to avoid the repeated call, keep the best digit sum next to the best number. This version gives the same answers on the three examples (95, 19 and 7), and it follows the same rule: it replaces the winner only when the new sum is strictly bigger.
fn biggest_digit_sum(nums: Vec<i32>) -> i32 {
let mut best = nums[0];
let mut best_sum = Self::digit_sum(best);
for num in &nums {
let s = Self::digit_sum(*num);
if s > best_sum {
best = *num;
best_sum = s;
}
}
return best;
}
Both versions are correct.
Common mistakes
- Returning the digit sum. The task wants the number itself. With
[472, 95, 1000]the answer is 95, not 14. - Using
>=for the comparison. The last of several tied numbers would win instead of the first.[19, 55, 28]would give 28. - Forgetting to divide by 10.
numnever changes and the loop runs forever. - Making the number the "biggest" itself. A larger number does not mean a larger digit sum: 1000 is far bigger than 95, but its digits add up to 1.
