Problem overview
The method biggestDigitSum gets an Array[Int] called nums and returns the number whose digits add up to the most. The digit sum of 472 is 4 + 7 + 2 = 13. If two numbers have the same digit sum, the one that comes first wins. The method returns the number itself, not its digit sum. Every number is between 0 and a billion, and there is at least one number.
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 19 wins the tie by coming first. For [0, 7] the sums are 0 and 7, so the answer is 7.
Approach
The work is split between two methods. The helper digitSum turns one number into the sum of its digits. biggestDigitSum does a "best so far" scan: it starts with the first number as the winner and replaces it whenever a number with a strictly bigger digit sum shows up. The helper is the only place that knows about digits. The scan only compares what the helper returns.
Step by step
The helper
- Parameters in Scala are
vals: they cannot be assigned. The loop must change a number, so copyninto a variable:var num = n. - Create
totalwithvar, starting at 0. - Loop with
while (num > 0). Each turn removes one digit, from the right. - Add the last digit with
total += num % 10. The remainder after dividing by 10 is the last digit: 472 % 10 is 2. - Drop that digit with
num = num / 10. Dividing twoIntvalues drops the remainder, so 472 / 10 is 47. - After the loop, return
total.
The main method
- Create
bestwithvar, starting atnums(0), the first number. - Loop with
for (num <- nums). - If
digitSum(num) > digitSum(best), setbest = num. Use>, not>=, so that on a tiebestkeeps the number that came first. - Return
best.
The solution in Scala
class Solution {
def digitSum(n: Int): Int = {
var num = n
var total = 0
while (num > 0) {
total += num % 10
num = num / 10
}
return total
}
def biggestDigitSum(nums: Array[Int]): Int = {
var best = nums(0)
for (num <- nums) {
if (digitSum(num) > digitSum(best)) {
best = num
}
}
return best
}
}
Array elements are read with parentheses in Scala, so the first number is nums(0). The loop starts with the first number again and compares it with itself, which changes nothing.
Why two methods
If the digit-taking loop sat inside the scan, the code would have a loop inside a loop, with num and total mixed together with best. As two methods, each loop has one job. The scan calls digitSum(num) and digitSum(best) and does not care how a sum is found. The helper can be tried on its own, for example on 1000, where it adds 0 + 0 + 0 + 1 and returns 1.
The scan calls the helper again for best on every turn. For a short array that is fine and keeps the code short. Storing the best sum in its own variable would avoid the repeat, but it adds a second variable to keep in step with best.
Testing
The helper returns 13 for 472, 14 for 95, 1 for 1000, 10 for each of 19, 55 and 28, and 0 for 0. With those sums the method returns 95, 19 and 7 on the three examples.
While the loop runs on 472, the pair (num, total) after each turn is (47, 2), then (4, 9), then (0, 13). The loop stops when num reaches 0 and the total is 13.
Another way
You can also get the digits from the number's text:
def digitSum(n: Int): Int = n.toString.map(_.asDigit).sum
This returns 13 for 472 and 0 for 0. Each character is turned into the digit it stands for, and the digits are added. The arithmetic version in the lesson avoids building a string and shows how % and / take a number apart, which is the skill this lesson practises.
For the main method, nums.maxBy(n => digitSum(n)) returns the first number with the biggest value, so on [19, 55, 28] it gives 19, like the lesson's scan.
Edge cases and common mistakes
- Changing the parameter. Writing
n = n / 10does not compile: the compiler reportsReassignment to val n. That is why the helper copiesnintonum. - Zero. For 0 the loop never runs, and the helper returns 0, which is correct.
- Ties. With
>=the tie in[19, 55, 28]would return 28, the last of the three. With>it returns 19, as the task asks. - Forgetting
num = num / 10. Thennumnever changes and the loop never ends. - Returning the digit sum. The method returns the number,
best, notdigitSum(best). - Overflow. Numbers up to a billion fit in an
Int(the largestIntis about 2.1 billion), so the sums and the divisions are safe.
