Start learning free

LESSON 192 OF 415 · NESTED LOOPS

Print X in Swift: Two Moving Columns

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 the first and the last column 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 of the line.
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 9
    Ctrl + Enter to check

    SWIFT · NESTED LOOPS

    Print X in Swift, explained

    Problem overview

    The method printX receives a positive integer n and prints n lines of n characters each. The two diagonals of the square are marked with x and every other position holds -. For n = 5:

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

    Approach: two column indices

    Looking at the output line by line, every line has the same shape: a few dashes with an x in two columns. On line 0 the columns are 0 and n - 1. On each following line the left x moves one column right and the right x moves one column left. So two variables, firstX and secondX, describe everything.

    In the middle line of an odd n the two indices are equal, which is why that line shows a single x. For an even n they cross over: for n = 4 the middle lines both read -xx-. No special case is needed in either situation, because a position is marked whenever it equals either index.

    Step by step

    1. Start the indices in one declaration, var firstX = 0, secondX = n - 1. Columns are numbered from 0, so the last one is n - 1.
    2. Loop n times with for _ in 0..<n. The loop variable is unused, because the indices carry all the state.
    3. Build the line by calling a helper and store it in a let constant, then print it.
    4. Move the indices: firstX += 1 and secondX -= 1. Swift has no ++ or --.
    5. Write the helper signature: buildString(_ n: Int, _ firstX: Int, _ secondX: Int) -> String, with no argument labels so the call stays short.
    6. Start with var str = "".
    7. Loop over each position i in 0..<n.
    8. Choose the character: if i == firstX || i == secondX append "x", otherwise "-". The || operator is true when either side is.
    9. Return str after the loop, once every position has been filled.

    The solution in Swift

    class Solution {
    
        func buildString(_ n: Int, _ firstX: Int, _ secondX: Int) -> String {
            var str = ""
            for i in 0..<n {
                if i == firstX || i == secondX {
                    str += "x"
                } else {
                    str += "-"
                }
            }
            return str
        }
    
        func printX(_ n: Int) {
            var firstX = 0, secondX = n - 1
            for _ in 0..<n {
                let line = buildString(n, firstX, secondX)
                print(line)
                firstX += 1
                secondX -= 1
            }
        }
    }
    

    Swift details:

    • Several variables in one var. var firstX = 0, secondX = n - 1 declares two Int variables; both are mutable.
    • let line. The line is never reassigned, so let is the right choice.
    • Strings can't be indexed by number. That is why the helper appends characters one at a time instead of editing a template string.

    Walking through n = 5

    Before the loop, firstX = 0 and secondX = 4. For line 0 the helper checks positions 0 to 4: position 0 equals firstX and position 4 equals secondX, giving x---x. The indices then become 1 and 3, which gives -x-x- for line 1. On line 2 both are 2, so position 2 matches both conditions and the line is --x--. From line 3 on, the indices have passed each other (3 and 1, then 4 and 0), which reproduces the first two lines in reverse order.

    Why it is a diagonal

    On line r (counting from 0), the left x is at column r and the right one is at column n - 1 - r. The first set of points, where row equals column, is the main diagonal; the second, where row plus column equals n - 1, is the anti-diagonal. The loop never computes these formulas; it just adds and subtracts 1 per line, which produces the same values. You could also write the condition directly as i == r || i == n - 1 - r if you had the line number r.

    The reason to keep separate indices is readability: the helper only needs to know which two columns are special, and does not care how they were found.

    Why a helper and not a nested loop

    The whole task could be written as two nested loops with a conditional inside. Splitting out buildString gives each method one job: printX decides which columns are special on each line, and the helper turns those two numbers into a string. That also lets you test the line-building logic on its own, for example by checking that buildString(5, 1, 3) returns -x-x-. Because the helper returns a String instead of printing, it can be reused later to collect the lines in an array or compare them with expected text.

    The helper's parameter names are the same as the variables in printX. That is fine: each method has its own scope, so the parameters firstX and secondX inside buildString receive the values passed in. Swift parameters are constants, so the helper can't even reassign them.

    Complexity

    Time: O(n²). n lines, each built by a loop of n steps.

    Space: O(n). One line of n characters exists at a time.

    Edge cases and common mistakes

    • n = 1. Both indices are 0, so the output is a single x.
    • Even n. printX(4) prints x--x, -xx-, -xx-, x--x.
    • Starting secondX at n. That column doesn't exist, so the right x would be missing on the first line and everything would be shifted.
    • Using && instead of ||. A position would need to equal both indices at once, which only happens in the middle of an odd square.
    • Returning inside the loop. The helper must return only after the loop, or it stops after the first character.

    Testing

    • printX(5) prints the five lines above.
    • printX(1) prints x.
    • printX(4) prints x--x, -xx-, -xx-, x--x.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free