Start learning free

LESSON 191 OF 414 · NESTED LOOPS

Print X in Scala: Nested Loops and Diagonals

Practice O(n2) Read the full explanation

Given a positive integer n print matrix containing an X as in the example below

Example:

Input: n = 5
Output:
x---x
-x-x-
--x--
-x-x-
x---x
Explanation:
Each line contains exactly n = 5 characters and two 'x's.
Each diagonal contains 'x'

Hints:

Notice that on each line there will be exactly two x and the other characters are all -. The only exception is the middle line which will have only one x. How can we use this info?

We can print the matrix line by line. For each line we need to know the two columns where we should print x. How can we know these two columns for every line?

We'll store the columns' indices in two variables firstX and secondX, initially equal to 0 and n - 1 respectively for the first line.
How should these variables change from line to line?

firstX should get incremented and secondX should get decremented.
Now for each line, you know the 'special' columns. How will you print that line?

We'll use a for loop to iterate through every column index from 0 to n - 1.
What should we do inside the loop?

We should use an if - else statement and check if the current index is firstX or secondX and if so, print x. Otherwise, print -.
STEP 1 OF 10
    Ctrl + Enter to check

    SCALA · NESTED LOOPS

    Print X in Scala, explained

    Problem overview

    The method printX receives a positive integer n and prints an n by n grid in which the two diagonals are made of x characters and every other cell is -. Each line is printed with println.

    For n = 5 the output is:

    x---x
    -x-x-
    --x--
    -x-x-
    x---x
    

    Every line has two x characters, except the middle line of an odd-sized grid, where both diagonals meet in the same cell and there is only one.

    Approach: two moving columns

    The cells that hold an x follow a simple pattern. On line 0, the x characters are in column 0 and column n - 1. On each next line, the first one moves one column to the right and the second one moves one column to the left, so the two approach each other until they cross in the middle.

    That means two integers, firstX and secondX, are enough to describe every line. For one line, check each column index: if it equals firstX or secondX, write x; otherwise write -. Then move the two numbers and repeat for the next line.

    The program has two parts, mirroring the idea: printX goes through the lines and moves the two numbers, and a helper, buildString, builds one line from n, firstX and secondX.

    Another way to see the same thing: on line i, the two x characters are in columns i and n - 1 - i. The lesson keeps two running variables instead of computing that formula, which gives the same positions and is easy to follow one line at a time. Both approaches look at every cell once, so neither changes the amount of work.

    Step by step

    1. Declare firstX and secondX with var, starting at 0 and n - 1. Both change on each line, so they can't be val.
    2. Loop over the lines with for (i <- 0 until n). The loop variable only counts the lines.
    3. Build and print the line. Call buildString(n, firstX, secondX), store the result in a val named str and pass it to println.
    4. Move the x positions. Add 1 to firstX and subtract 1 from secondX. Scala has no ++ or --, so use += 1 and -= 1.
    5. Write the helper's signature. It takes three Int values and returns a String.
    6. Start with an empty var string that collects the characters of the line.
    7. Loop over the column indices with 0 until n.
    8. Append "x" when the column equals firstX or secondX. The || operator is true when at least one of its sides is true.
    9. Append "-" otherwise.
    10. Return the string after the loop, once every column has been decided.

    The solution in Scala

    class Solution {
    
        def printX(n: Int): Unit = {
            var firstX = 0
            var secondX = n - 1
            for (i <- 0 until n) {
                val str = buildString(n, firstX, secondX)
                println(str)
                firstX += 1
                secondX -= 1
            }
        }
    
        def buildString(n: Int, firstX: Int, secondX: Int): String = {
            var str = ""
            for (i <- 0 until n) {
                if (i == firstX || i == secondX) {
                    str += "x"
                } else {
                    str += "-"
                }
            }
            return str
        }
    }
    

    The Scala details worth a closer look:

    • Two variables called str. The one in printX is a val holding one finished line, and the one in buildString is a separate var. Each lives only inside its own method, so they don't interfere.
    • Parameters are read-only. The helper's parameters firstX and secondX have the same names as the variables in printX, but they are separate copies of the values. The helper cannot change the caller's variables, and it couldn't reassign its own parameters either.
    • if / else as a statement. Both branches only change str, so the if is used for its effect here. In Scala, if is also an expression with a value, so str += (if (cond) "x" else "-") would do the same.
    • == compares values. For Int, that is what is wanted. For strings and other objects, Scala's == calls equals, so it compares contents rather than references.
    • return is optional. The last expression of a block is its value, so str alone on the last line would be enough.

    Complexity

    Time: O(n²). The method prints n lines, and each line is built by looping over n columns.

    Space: O(n). Only one line exists at a time, and the counters are plain integers.

    Edge cases and common mistakes

    • n = 1. Both positions are 0, so the single line is x.
    • Even n. The two diagonals never share a cell, so every line has two x characters. For n = 4 the output is x--x, -xx-, -xx-, x--x. For n = 2 it is xx twice.
    • The middle line of an odd n. Both positions are equal there, so the same condition catches them and prints one x. No special case is needed.
    • Starting at 1 instead of 0. Columns here are numbered from 0, as with every Scala index. Starting firstX at 1 and secondX at n shifts the diagonals by one column, and secondX would start at column n, which is outside the line.
    • Using && instead of ||. A column can't be both positions, except in the middle, so almost no x would be printed.
    • Forgetting to move the counters. Without the two updates, every line looks like the first.
    • Returning inside the loop. A return str placed inside the loop in buildString ends it after the first column, so every line would have a single character.

    Testing

    • n = 1 prints x.
    • n = 2 prints xx twice.
    • n = 4 prints x--x, -xx-, -xx-, x--x.
    • n = 5 prints the five lines shown above.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free