Start learning free

LESSON 182 OF 415 · LOOPS - CHALLENGES

Fizz Buzz in Swift: A for Loop with the Modulo Operator

Practice O(n) Read the full explanation

Given a positive integer n print each number from 1 to n, each on a new line.
For each multiple of 3, print "Fizz" instead of the number.
For each multiple of 5, print "Buzz" instead of the number.
For numbers which are multiples of both 3 and 5, print "FizzBuzz" instead of the number.

Example:

Input: n = 15
Output:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

Note:

Your algorithm should run in O(n) time and use O(1) space.


Hints:

In order to print the items, we should iterate through the numbers 1 to n and check for each of them what condition is satisfied to print accordingly. How can we do this?

Let's use a for loop and a variable i to iterate through the numbers 1 to n:
for each i from 1 to n:
	print either i or "Fizz" or "Buzz" or "FizzBuzz"
Inside the loop, we need to decide what should be printed between Fizz, Buzz, FizzBuzz and i.
How can we do this?

Using sequential if - else statements along with the modulo (%) operator, which gives the remainder of a division (i % 15 == 0 means that i is divisible by 15):
for each i from 1 to n:
	if i is divisible by 15, print "FizzBuzz"
	otherwise, if i is divisible by 3, print "Fizz"
	otherwise, if i is divisible by 5, print "Buzz"
	otherwise, print i

We have a for loop that performs exactly n iterations, thus the Time Complexity is O(n).
The only extra space we use is the iterator variable i inside the loop, thus the Extra Space used is O(1).

Video Solution:

STEP 1 OF 5
    Ctrl + Enter to check

    SWIFT · LOOPS - CHALLENGES

    Fizz Buzz in Swift, explained

    Problem overview

    The method fizzBuzz(_ n: Int) prints the numbers from 1 to n, one per line, with three replacements: multiples of 3 print Fizz, multiples of 5 print Buzz, and numbers that are multiples of both print FizzBuzz. It returns nothing.

    For n = 15 the output is: 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz. The statement asks for O(n) time and O(1) space.

    Approach

    Visit each number once and decide what to print for it. The decision uses the remainder operator %: i % 3 == 0 means i is a multiple of 3. The one subtle point is the order of the checks. A number divisible by both 3 and 5 also passes the "multiple of 3" test, so the combined case must be tested first. A number is a multiple of both exactly when it is a multiple of 15, because 3 and 5 share no factor.

    Step by step

    1. Loop from 1 to n with the closed range 1...n, which includes n.
    2. Check 15 first. If i % 15 == 0, print FizzBuzz.
    3. Then check 3, in an else if branch, and print Fizz.
    4. Then check 5 and print Buzz.
    5. Otherwise print the number itself in the final else.

    The solution in Swift

    class Solution {
        func fizzBuzz(_ n: Int) {
            for i in 1...n {
                if i % 15 == 0 {
                    print("FizzBuzz")
                } else if i % 3 == 0 {
                    print("Fizz")
                } else if i % 5 == 0 {
                    print("Buzz")
                } else {
                    print(i)
                }
            }
        }
    }
    

    Swift details:

    • 1...n is a closed range, and the loop constant i is a fresh Int on each pass. Swift also allows 1...n only when n is at least 1; a range like 1...0 stops the program at run time. The statement promises a positive n, so this is safe here.
    • print accepts both strings and integers, and adds the newline.
    • The conditions have no parentheses, but the braces around each branch are mandatory.
    • A switch on the pair of remainders, such as switch (i % 3, i % 5), is a common alternative, but the if chain is the simplest.

    Why check 15 and not "3 and 5"

    Writing i % 3 == 0 && i % 5 == 0 is equally correct and arguably reads more directly. The % 15 form works because a number divisible by two coprime numbers is divisible by their product. Whichever you pick, the rule is the same: the most specific condition goes first, and each later branch only runs for numbers that failed the earlier ones. That is what lets the else if branches stay short: when the % 3 test runs, you already know the number is not a multiple of 15.

    The remainder operator

    The operator % gives the remainder after integer division, so 15 % 3 is 0 and 7 % 3 is 1. A remainder of 0 means the first number divides evenly. In Swift, % works on integers and takes the sign of the left operand, so -3 % 5 is -3. That doesn't matter here, since i is never negative, but it is worth remembering when you test divisibility on numbers that can be.

    Tracing a few values

    ii % 15i % 3i % 5Printed
    77127
    9904Fizz
    101010Buzz
    15000FizzBuzz

    Other ways to write it

    Instead of testing 15 explicitly, you can build the word from pieces and fall back to the number when the word stays empty:

    func fizzBuzz2(_ n: Int) {
        for i in 1...n {
            var word = ""
            if i % 3 == 0 { word += "Fizz" }
            if i % 5 == 0 { word += "Buzz" }
            print(word.isEmpty ? String(i) : word)
        }
    }
    

    This prints the same 15 lines for n = 15. Swift's switch must be exhaustive and can match a tuple of remainders, which makes the four cases explicit:

    func fizzBuzz3(_ n: Int) {
        for i in 1...n {
            switch (i % 3, i % 5) {
            case (0, 0): print("FizzBuzz")
            case (0, _): print("Fizz")
            case (_, 0): print("Buzz")
            default: print(i)
            }
        }
    }
    

    This also prints the same output. Both variants are still O(n) time. The lesson's version is the shortest to read, and the other two are worth knowing because they scale better when more rules (say, a "Bazz" for 7) are added: the string-building form needs one new line, while the if chain needs a new combination for every pair of rules.

    Complexity

    Time: O(n). The loop runs exactly n times and each pass does a constant amount of work. Space: O(1). Only the loop constant is used, and the output is printed, not stored.

    Edge cases and common mistakes

    • Testing 3 before 15. Then 15 prints Fizz and the FizzBuzz branch can never run.
    • Using two independent if statements without an else, which prints both a word and the number for some inputs.
    • Using 1..<n. The half-open range stops before n, so the last line is missing.
    • n = 1. Prints just 1.
    • Starting at 0. A loop for i in 0..<n looks natural but is wrong twice. It prints a line for 0, and since 0 % 15 == 0 that line is FizzBuzz; it also stops before n. The range 1...n fixes both.
    • Printing extra text. The output must be the exact words or numbers, one per line. Adding labels, commas or spaces around them makes the lines differ from the expected ones.
    • Returning instead of printing. The method has no return value. Collecting the lines in an array and returning it would leave the console empty.
    • Spelling. The words are case-sensitive: Fizz, Buzz, FizzBuzz.

    Testing

    • fizzBuzz(15) prints the sequence from the example, ending in FizzBuzz.
    • fizzBuzz(5) prints 1, 2, Fizz, 4, Buzz.
    • fizzBuzz(1) prints 1.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free