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
- Start the indices in one declaration,
var firstX = 0, secondX = n - 1. Columns are numbered from 0, so the last one isn - 1. - Loop
ntimes withfor _ in 0..<n. The loop variable is unused, because the indices carry all the state. - Build the line by calling a helper and store it in a
letconstant, then print it. - Move the indices:
firstX += 1andsecondX -= 1. Swift has no++or--. - Write the helper signature:
buildString(_ n: Int, _ firstX: Int, _ secondX: Int) -> String, with no argument labels so the call stays short. - Start with
var str = "". - Loop over each position
iin0..<n. - Choose the character: if
i == firstX || i == secondXappend"x", otherwise"-". The||operator is true when either side is. - Return
strafter 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 - 1declares twoIntvariables; both are mutable. let line. The line is never reassigned, soletis 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 singlex.- Even
n.printX(4)printsx--x,-xx-,-xx-,x--x. - Starting
secondXatn. That column doesn't exist, so the rightxwould 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)printsx.printX(4)printsx--x,-xx-,-xx-,x--x.
