Start learning free

LESSON 192 OF 414 · NESTED LOOPS

Print Triangle of Stars in Rust: Building a String in a Loop

Practice O(n2) Read the full explanation

Given a positive integer n print a triangle of stars as in the example below

Example:

Input: n = 5
Output:
*
**
***
****
*****
Explanation: Print 5 lines, on ith line print i stars.
STEP 1 OF 4
    Ctrl + Enter to check

    RUST · NESTED LOOPS

    Print Triangle Of Stars in Rust, explained

    Problem overview

    The function print_stars receives a positive integer n as an i32 and prints a triangle of stars: n lines, where line number i holds exactly i stars. It prints the triangle and returns nothing.

    For n = 5 the output is:

    *
    **
    ***
    ****
    *****
    

    Every line is the line above it plus one more star. That observation is the whole solution.

    Approach: grow one row and print it each time

    One way to solve it is to compute, for each line number i, a string of i stars and print it. That works, but the rows have a simpler relationship: row 2 is row 1 with a star added at the end, row 3 is row 2 with a star added, and so on.

    So the program keeps a single String that starts empty. On each of the n passes of a loop it appends one star and prints the string. The first pass prints one star, the second prints two, and the nth prints n. Nothing needs to be counted, because the string itself remembers how many stars it holds.

    Step by step

    1. Create the row. Declare stars as an empty String with String::new(). It needs let mut, because the loop changes it, and Rust variables are immutable unless marked otherwise.
    2. Loop n times. The range 0..n excludes n, so it produces exactly n values, one per line. The loop variable is never read, so it is named _.
    3. Add one star to the end of stars with push.
    4. Print the row with println!, still inside the loop and after the push. Each call ends with a newline, so every row lands on its own line.

    The order of steps 3 and 4 matters. If the loop printed first and pushed afterwards, the first line would be empty and the last line would be missing.

    The solution in Rust

    impl Solution {
        fn print_stars(n: i32) {
            let mut stars = String::new();
            for _ in 0..n {
                stars.push('*');
                println!("{}", stars);
            }
        }
    }
    

    A few Rust details in these lines:

    • Why stars and not str. str is the name of Rust's string slice type, so a variable called stars is the clearer choice.
    • push takes a char. A char is written with single quotes, '*'. Writing stars.push("*") with double quotes is a compile error: the compiler expects a char and finds a &str. To append a whole string slice, use push_str("**").
    • mut is required. Without it, stars.push('*') fails to compile with "cannot borrow stars as mutable, as it is not declared as mutable".
    • println! is a macro. The ! marks it as one. The {} in its format string is replaced by the next argument, here stars, and a newline is added after the text.
    • The function returns (). There is no -> in the signature, so nothing is returned. The function's result is its printed output.
    • Range loops. 0..n is a half-open range of i32 values here, because n is an i32. If n is 0 or negative the range is empty and the body never runs.

    Complexity

    Time: O(n²). The loop runs n times, but printing row i writes i characters, so the total output is 1 + 2 + ... + n = n(n + 1)/2 characters. Any solution has to print that many characters, so the quadratic cost comes from the size of the output, not from the method.

    Space: O(n). The only extra memory is the String, which grows to n characters.

    Edge cases and common mistakes

    • n = 1. The loop runs once and prints a single *.
    • n = 0. The range 0..0 is empty, so nothing is printed. A negative n behaves the same way.
    • Printing after the loop. Only the last row would appear, because the string holds the full row by then.
    • Declaring the string inside the loop. A fresh empty string on every pass would print one star on every line.
    • Using print!. Unlike println!, it adds no newline, so all the stars would end up on one line.
    • Using "*" with push. Double quotes make a string slice, and push wants a char.

    Testing

    • n = 1 prints *.
    • n = 3 prints *, ** and *** on three lines.
    • n = 0 prints nothing.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free