Problem overview
The method fizzBuzz(n) prints the numbers from 1 to n, one per line, with three substitutions. A multiple of 3 prints Fizz instead of the number. A multiple of 5 prints Buzz. A multiple of both 3 and 5 prints FizzBuzz. For n = 15 the output starts 1, 2, Fizz, 4, Buzz, and ends with 13, 14, FizzBuzz. The method prints and returns nothing.
The statement asks for O(n) time and O(1) extra space. A single pass over the numbers does that.
Approach: one loop, one decision per number
Loop over i from 1 to n. For each value, decide which of four outputs applies: FizzBuzz, Fizz, Buzz or the number itself. The test for "multiple of k" is i % k === 0: the remainder operator % gives what is left after dividing, so a remainder of 0 means i divides evenly by k.
The order of the checks is the key point. A number such as 15 is a multiple of 3 and also of 5, so it satisfies the "Fizz" test and the "Buzz" test. If you test 3 first, you print Fizz and never reach the case you needed. The combined case must come first. A number is a multiple of both 3 and 5 exactly when it is a multiple of 15, so a single check i % 15 === 0 handles it.
Printing is also the only output: the method has no return value, so nothing is collected in an array. That is why the extra space stays constant however large n is.
Step by step
- Write a
forloop withlet i = 1that continues whilei <= n. It starts at 1, not 0, and includesn. - Check
i % 15 === 0first and print"FizzBuzz". - Chain an
else iffor 3 and print"Fizz". - Chain another
else iffor 5 and print"Buzz". - Finish with
elseand print the numberi.
Because the branches are chained with else if, at most one of them runs for each number.
The solution in TypeScript
class Solution {
fizzBuzz(n: number): void {
for (let i = 1; i <= n; i++) {
if (i % 15 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
}
}
Two details are worth knowing. First, the comparisons use ===, the strict equality operator, which never converts types. It is the habit to keep in TypeScript, since == can convert values in surprising ways. Second, console.log(i) prints a number and console.log("Fizz") prints a string, but both appear as plain text on a line, with no quotes. The parameter n has type number, and TypeScript has no separate integer type, so the type doesn't stop a caller from passing 2.5; the lesson promises a positive integer.
How the remainder works
The expression 7 % 3 is 1, because 7 is two threes and one left over. 15 % 5 is 0, because 5 goes into 15 exactly, and 4 % 5 is 4, because 5 doesn't fit into 4 at all. Only a remainder of 0 means "multiple". Operator precedence puts % before ===, so i % 15 === 0 needs no extra parentheses.
Another way to organise the checks
If the multiple-of-15 shortcut feels like a trick, you can build the word from its parts and print the number only when no part was added:
function fizzBuzz2(n: number): void {
for (let i = 1; i <= n; i++) {
let word = "";
if (i % 3 === 0) word += "Fizz";
if (i % 5 === 0) word += "Buzz";
console.log(word === "" ? i : word);
}
}
For 15 both conditions hold, so word becomes "FizzBuzz" by itself, and the order of the checks no longer matters. The output for n = 15 is the same as the lesson's. This version also extends well: adding a rule for 7 is one more line. The lesson's version is shorter to read for exactly two rules.
Complexity
The loop runs exactly n times and each iteration does a fixed number of remainder checks and one print, so the time is O(n). The only extra variable is the loop index i, so the extra space is O(1).
Edge cases and common mistakes
- Testing 3 or 5 before 15. The output for 15 becomes
Fizz, and so does every other multiple of 15. This is the classic mistake. - Using two independent
ifs withoutelse. Then 15 would printFizzand alsoBuzzon separate lines. If you want separate checks, build a string instead and print the number only when the string is empty. - Off-by-one loop bounds. Starting at 0 would print
FizzBuzzfirst, because 0 is a multiple of everything. Stopping ati < nwould dropn. - An input of 0 or less. The loop condition
1 <= nis false at once, so nothing is printed. The lesson promises a positiven, but it is good to know what the loop does without that promise. - Using
=instead of===in a condition. That assigns instead of comparing.
Testing
With n = 5 the output is 1, 2, Fizz, 4, Buzz. With n = 1 it is just 1. With n = 15 the last line is FizzBuzz, the only line that needs the combined case.