412. Fizz Buzz
Problem Description
This is the classic FizzBuzz problem. You're given an integer n
, and you need to create and return a string array containing n
elements (indexed from 1 to n).
For each position i
from 1 to n
, you need to determine what string to place in the array based on these rules:
- If
i
is divisible by both 3 and 5, add"FizzBuzz"
- If
i
is divisible by only 3, add"Fizz"
- If
i
is divisible by only 5, add"Buzz"
- If
i
is not divisible by 3 or 5, add the number itself as a string (e.g.,"7"
)
The solution iterates through numbers from 1 to n
. For each number, it first checks if it's divisible by 15 (which means divisible by both 3 and 5), then checks divisibility by 3 alone, then by 5 alone. If none of these conditions are met, the number is converted to a string and added to the result array.
For example, if n = 15
, the output would be:
["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"]
The key insight in the solution is checking divisibility by 15 first (using i % 15 == 0
), which is equivalent to checking if a number is divisible by both 3 and 5, since 15 is the least common multiple of 3 and 5.
Intuition
The problem asks us to process each number from 1 to n
and apply different transformations based on divisibility rules. The natural approach is to check each number sequentially and determine which rule applies.
The key observation is that numbers divisible by both 3 and 5 are actually divisible by 15 (since 15 is the least common multiple of 3 and 5). This means we can simplify our checks by testing for divisibility by 15 directly instead of checking both conditions separately.
The order of checking conditions matters. We must check for divisibility by 15 first because these numbers are also divisible by 3 and by 5. If we checked for divisibility by 3 or 5 first, we'd never reach the "FizzBuzz" case. For example, the number 15 is divisible by 3, so if we check i % 3 == 0
first, we'd incorrectly output "Fizz" instead of "FizzBuzz".
This leads to a straightforward if-else chain:
- First check if the number is divisible by both 3 and 5 (using
i % 15 == 0
) - Then check if it's divisible by just 3
- Then check if it's divisible by just 5
- If none of the above, use the number itself
Since we need to process every number from 1 to n
exactly once and apply a constant-time check for each, a simple loop with conditional statements gives us an efficient solution with O(n)
time complexity.
Solution Approach
The solution uses a simple simulation approach, iterating through each integer from 1 to n
and applying the divisibility rules to determine the appropriate string to add to our result array.
Implementation Steps:
-
Initialize an empty list
ans
to store our results. -
Iterate through numbers from 1 to
n
(inclusive) usingrange(1, n + 1)
. -
Apply divisibility checks for each number
i
:- First check
i % 15 == 0
: If true, the number is divisible by both 3 and 5, so append"FizzBuzz"
. - Else check
i % 3 == 0
: If true, the number is divisible by 3, so append"Fizz"
. - Else check
i % 5 == 0
: If true, the number is divisible by 5, so append"Buzz"
. - Otherwise: Convert the number to a string using
str(i)
and append it.
- First check
-
Return the result array after processing all numbers.
Why this order of checks? The condition for "FizzBuzz" (divisible by both 3 and 5) must be checked first. If we checked divisibility by 3 or 5 first, numbers like 15, 30, 45 would incorrectly produce "Fizz" or "Buzz" instead of "FizzBuzz" since they satisfy all three conditions.
Data Structure: We use a simple list/array to collect our results, which is the most natural choice since we need to return a collection of strings in order.
Time and Space Complexity:
- Time:
O(n)
- We process each number from 1 ton
exactly once. - Space:
O(n)
- We storen
strings in our result array.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 6
to see how each number is processed:
Step 1: Initialize empty result array: ans = []
Step 2: Process i = 1
- Check
1 % 15 == 0
? No (1 ÷ 15 = 0 remainder 1) - Check
1 % 3 == 0
? No (1 ÷ 3 = 0 remainder 1) - Check
1 % 5 == 0
? No (1 ÷ 5 = 0 remainder 1) - None match, so append
"1"
- Result:
["1"]
Step 3: Process i = 2
- Check
2 % 15 == 0
? No - Check
2 % 3 == 0
? No - Check
2 % 5 == 0
? No - None match, so append
"2"
- Result:
["1", "2"]
Step 4: Process i = 3
- Check
3 % 15 == 0
? No (3 ÷ 15 = 0 remainder 3) - Check
3 % 3 == 0
? Yes (3 ÷ 3 = 1 remainder 0) - Append
"Fizz"
- Result:
["1", "2", "Fizz"]
Step 5: Process i = 4
- Check
4 % 15 == 0
? No - Check
4 % 3 == 0
? No - Check
4 % 5 == 0
? No - None match, so append
"4"
- Result:
["1", "2", "Fizz", "4"]
Step 6: Process i = 5
- Check
5 % 15 == 0
? No (5 ÷ 15 = 0 remainder 5) - Check
5 % 3 == 0
? No (5 ÷ 3 = 1 remainder 2) - Check
5 % 5 == 0
? Yes (5 ÷ 5 = 1 remainder 0) - Append
"Buzz"
- Result:
["1", "2", "Fizz", "4", "Buzz"]
Step 7: Process i = 6
- Check
6 % 15 == 0
? No - Check
6 % 3 == 0
? Yes (6 ÷ 3 = 2 remainder 0) - Append
"Fizz"
- Result:
["1", "2", "Fizz", "4", "Buzz", "Fizz"]
Final Output: ["1", "2", "Fizz", "4", "Buzz", "Fizz"]
Notice how the order of checks matters. If we encounter i = 15
, it would satisfy all three divisibility conditions (15 % 3 == 0, 15 % 5 == 0, and 15 % 15 == 0). By checking 15 first, we correctly output "FizzBuzz" instead of stopping at "Fizz" or "Buzz".
Solution Implementation
1class Solution:
2 def fizzBuzz(self, n: int) -> List[str]:
3 """
4 Generate FizzBuzz sequence from 1 to n.
5
6 Args:
7 n: The upper limit of the sequence (inclusive)
8
9 Returns:
10 A list of strings where:
11 - Numbers divisible by 3 are replaced with "Fizz"
12 - Numbers divisible by 5 are replaced with "Buzz"
13 - Numbers divisible by both 3 and 5 are replaced with "FizzBuzz"
14 - All other numbers are converted to strings
15 """
16 result = []
17
18 # Iterate through numbers from 1 to n (inclusive)
19 for num in range(1, n + 1):
20 # Check divisibility by 15 first (divisible by both 3 and 5)
21 if num % 15 == 0:
22 result.append('FizzBuzz')
23 # Check divisibility by 3
24 elif num % 3 == 0:
25 result.append('Fizz')
26 # Check divisibility by 5
27 elif num % 5 == 0:
28 result.append('Buzz')
29 # For all other numbers, append the string representation
30 else:
31 result.append(str(num))
32
33 return result
34
1class Solution {
2 /**
3 * Generates a FizzBuzz sequence from 1 to n.
4 *
5 * @param n The upper limit of the sequence (inclusive)
6 * @return A list of strings representing the FizzBuzz sequence
7 *
8 * Rules:
9 * - Numbers divisible by 3 are replaced with "Fizz"
10 * - Numbers divisible by 5 are replaced with "Buzz"
11 * - Numbers divisible by both 3 and 5 are replaced with "FizzBuzz"
12 * - All other numbers are converted to their string representation
13 */
14 public List<String> fizzBuzz(int n) {
15 // Initialize the result list to store the FizzBuzz sequence
16 List<String> result = new ArrayList<>();
17
18 // Iterate through numbers from 1 to n (inclusive)
19 for (int currentNumber = 1; currentNumber <= n; currentNumber++) {
20 // Build the string representation for the current number
21 String currentString = "";
22
23 // Check if divisible by 3
24 if (currentNumber % 3 == 0) {
25 currentString += "Fizz";
26 }
27
28 // Check if divisible by 5
29 if (currentNumber % 5 == 0) {
30 currentString += "Buzz";
31 }
32
33 // If not divisible by 3 or 5, use the number itself
34 if (currentString.length() == 0) {
35 currentString += currentNumber;
36 }
37
38 // Add the processed string to the result list
39 result.add(currentString);
40 }
41
42 return result;
43 }
44}
45
1class Solution {
2public:
3 vector<string> fizzBuzz(int n) {
4 // Initialize result vector to store output strings
5 vector<string> result;
6
7 // Iterate through numbers from 1 to n inclusive
8 for (int i = 1; i <= n; ++i) {
9 // Initialize current string for this number
10 string currentString = "";
11
12 // Check if number is divisible by 3
13 if (i % 3 == 0) {
14 currentString += "Fizz";
15 }
16
17 // Check if number is divisible by 5
18 if (i % 5 == 0) {
19 currentString += "Buzz";
20 }
21
22 // If not divisible by 3 or 5, use the number itself
23 if (currentString.empty()) {
24 currentString = to_string(i);
25 }
26
27 // Add the resulting string to the result vector
28 result.push_back(currentString);
29 }
30
31 // Return the complete result vector
32 return result;
33 }
34};
35
1/**
2 * Generates an array of strings following the FizzBuzz pattern
3 * @param n - The upper limit of the range (inclusive)
4 * @returns An array of strings where multiples of 3 are "Fizz",
5 * multiples of 5 are "Buzz", multiples of both are "FizzBuzz",
6 * and other numbers are their string representation
7 */
8function fizzBuzz(n: number): string[] {
9 // Initialize the result array to store FizzBuzz sequence
10 const result: string[] = [];
11
12 // Iterate through numbers from 1 to n (inclusive)
13 for (let i = 1; i <= n; i++) {
14 // Check if divisible by both 3 and 5 (i.e., divisible by 15)
15 if (i % 15 === 0) {
16 result.push('FizzBuzz');
17 }
18 // Check if divisible by 3 only
19 else if (i % 3 === 0) {
20 result.push('Fizz');
21 }
22 // Check if divisible by 5 only
23 else if (i % 5 === 0) {
24 result.push('Buzz');
25 }
26 // For all other numbers, add the number as a string
27 else {
28 result.push(i.toString());
29 }
30 }
31
32 return result;
33}
34
Time and Space Complexity
Time Complexity: O(n)
The algorithm iterates through numbers from 1 to n exactly once using a single for loop. In each iteration, it performs constant-time operations: modulo calculations (%
), comparisons, and appending to a list. Since we perform a constant amount of work for each of the n numbers, the overall time complexity is O(n)
, where n
is the input integer.
Space Complexity: O(1)
(excluding the output array)
If we exclude the space required for the output array ans
(which is necessary to store the result), the algorithm uses only a constant amount of extra space. The only additional variable used is the loop iterator i
, which requires O(1)
space regardless of the input size. No additional data structures or recursive calls are made that would scale with the input.
If we include the output array in our space complexity analysis, it would be O(n)
since we store exactly n
strings in the result list.
Common Pitfalls
1. Incorrect Order of Conditional Checks
The Pitfall: A frequent mistake is checking for divisibility by 3 or 5 before checking for divisibility by both. This leads to incorrect output for numbers that are multiples of 15.
Incorrect Implementation:
# WRONG - This will never print "FizzBuzz"
for num in range(1, n + 1):
if num % 3 == 0:
result.append('Fizz') # 15 would stop here
elif num % 5 == 0:
result.append('Buzz')
elif num % 15 == 0: # This condition is unreachable for multiples of 15
result.append('FizzBuzz')
else:
result.append(str(num))
Why It Fails:
When num = 15
, the first condition num % 3 == 0
evaluates to true, so the code appends "Fizz" and never reaches the check for divisibility by 15.
The Solution: Always check the most restrictive condition first. Since numbers divisible by both 3 and 5 are a subset of numbers divisible by 3 (and also a subset of numbers divisible by 5), check for divisibility by 15 before checking for divisibility by 3 or 5 individually.
Correct Implementation:
for num in range(1, n + 1):
if num % 15 == 0: # Most restrictive condition first
result.append('FizzBuzz')
elif num % 3 == 0:
result.append('Fizz')
elif num % 5 == 0:
result.append('Buzz')
else:
result.append(str(num))
2. Using Separate Conditions Instead of elif
The Pitfall:
Using multiple independent if
statements instead of elif
can lead to multiple strings being appended for a single number.
Incorrect Implementation:
# WRONG - Multiple conditions can be true for the same number
for num in range(1, n + 1):
if num % 3 == 0:
result.append('Fizz')
if num % 5 == 0: # This is a separate check, not elif
result.append('Buzz')
if num % 15 == 0:
result.append('FizzBuzz')
if num % 3 != 0 and num % 5 != 0:
result.append(str(num))
Why It Fails:
For num = 15
, all three conditions involving modulo operations would be true, resulting in three strings ("Fizz", "Buzz", and "FizzBuzz") being appended instead of just "FizzBuzz".
The Solution:
Use elif
statements to ensure only one condition is executed per number, creating mutually exclusive branches.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!