Problem overview
The method fizzBuzz(n: Int) prints the numbers from 1 to n, one per line, but replaces some of them with words. A multiple of 3 prints Fizz, a multiple of 5 prints Buzz, and a multiple of both prints FizzBuzz. Every other number prints as itself.
For n = 15 the output starts 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14 and ends with FizzBuzz, because 15 is a multiple of both 3 and 5.
Approach
The method looks at each number once and decides what to print. The only difficulty is the order of the checks. A multiple of 15 is also a multiple of 3 and of 5, so if you test for 3 first, 15 would print Fizz and never reach the FizzBuzz case. Test the most specific condition first, then the others.
A number is a multiple of both 3 and 5 exactly when it is a multiple of 15, so one test i % 15 == 0 handles that case.
Here is how the chain treats a few values of i:
i | Remainders by 15, 3, 5 | First test that succeeds | Printed |
|---|---|---|---|
| 2 | 2, 2, 2 | none | 2 |
| 9 | 9, 0, 4 | i % 3 == 0 | Fizz |
| 10 | 10, 1, 0 | i % 5 == 0 | Buzz |
| 30 | 0, 0, 0 | i % 15 == 0 | FizzBuzz |
Because the chain stops at the first test that succeeds, 30 never reaches the Fizz or Buzz lines.
How the remainder test works
The expression i % 3 is the remainder after dividing i by 3. It is always 0, 1 or 2, and it is 0 exactly when i is a multiple of 3. For 9 the remainder is 0, for 10 it is 1, and for 11 it is 2. The same idea works for any divisor: i % 5 == 0 picks out 5, 10, 15 and so on. Both operands here are Int, so the result is an Int and compares directly with the literal 0.
Notice that the pattern repeats every 15 numbers: 3 and 5 both divide 15, so the numbers 16 to 30 get words in exactly the same positions as 1 to 15: 18 is Fizz like 3, 20 is Buzz like 5, and 30 is FizzBuzz like 15. The loop does not rely on that repetition, but it explains why the single test for 15 is enough. Each test only looks at the current number, so the loop keeps no state between passes and the order of the lines is the order of the numbers.
Step by step
- Loop from 1 to
ninclusive withfor (i <- 1 to n). The wordtoincludes the upper bound. - Check
i % 15 == 0first and printFizzBuzz. The remainder operator%gives 0 whenidivides evenly. - Then check
i % 3 == 0and printFizz. Only numbers that are not multiples of 15 reach this line. - Then check
i % 5 == 0and printBuzz. - Otherwise print
iitself. This is the finalelse.
The solution in Scala
class Solution {
def fizzBuzz(n: Int): Unit = {
for (i <- 1 to n) {
if (i % 15 == 0) {
println("FizzBuzz")
} else if (i % 3 == 0) {
println("Fizz")
} else if (i % 5 == 0) {
println("Buzz")
} else {
println(i)
}
}
}
}
Some Scala details:
1 to nis a range.for (i <- 1 to n)runs foriequal to 1, 2, ...,n.1 until nwould stop atn - 1and drop the last line. Ifnis 0,1 to 0is empty, so nothing is printed.iis avalinside the loop. You cannot assign to it. Each pass gets a fresh value from the range.printlnaccepts any value.println("Fizz")prints a string andprintln(i)prints anInt, both followed by a line break. No conversion is needed.- Everything is an expression. The
if/else ifchain here is used for its side effects, and every branch has typeUnit, so the loop body is aUnittoo. %keeps the sign of the dividend. This does not matter here, becauseiis always positive.
An alternative: build the word
The 15 test hard-codes the fact that 3 times 5 is 15. A version that grows if a third word is added builds the text from parts: start with an empty string, append Fizz when i % 3 == 0, append Buzz when i % 5 == 0, and print the number only if the string is still empty. For i = 15 both appends happen, which produces FizzBuzz without a separate case. This version prints the same output for n = 15. The lesson uses the chain of tests, which is the simpler form to read.
Complexity
Time: O(n). The loop runs exactly n times and each pass does at most three remainder tests and one print.
Space: O(1). The only extra value is the loop variable i.
Edge cases and common mistakes
- Wrong order of checks. With the 3 test first, 15 prints
Fizzinstead ofFizzBuzz. Another correct way is to testi % 3 == 0 && i % 5 == 0first. - Using
until.1 until nnever reachesn, so forn = 15the finalFizzBuzzline would be missing. - Printing a word and the number. Each number produces exactly one line. Use
else, not a separateifthat also printsi. - Spelling. The words are case-sensitive:
fizzbuzzandFizzbuzzdo not matchFizzBuzz. n = 1. The loop prints a single line,1.
Testing
n = 1prints1.n = 5prints1,2,Fizz,4,Buzz.n = 15ends with14andFizzBuzz.
