Problem overview
The method printRhombus receives an odd positive integer n and prints a rhombus of stars: n lines, each exactly n characters wide. For n = 5 the output is:
*
***
*****
***
*
The first line holds two spaces, one star and two spaces. The stars grow by two per line until the middle line, which is all stars, and then shrink by two per line. The spaces after the last star count: every line must be exactly n characters long.
Approach: track two counters
Each line is described by two numbers: how many stars it has, and how many spaces sit on each side. The first line has one star and n / 2 spaces per side. Moving down, each line gains one star on each side of the centre, so stars goes up by 2 and spaces goes down by 1. After the middle line the changes reverse.
With n = 5, the pairs (spaces, stars) are (2, 1), (1, 3), (0, 5), (1, 3), (2, 1). Notice that spaces * 2 + stars is always n, which is why the line width stays fixed.
Swift has no built-in "repeat this string" operator, so the lesson writes a small helper, buildString, that appends a one-character string n times. (The standard library does offer String(repeating: " ", count: n), which does the same job.)
Step by step
- Declare
starswithvar, starting at 1. It changes every line, so it can't belet. - Declare
spaceswithvar, starting atn / 2. Integer division drops the remainder, so for an oddnthis is exactly the number of spaces beside the single star. - Loop over
0..<n, one pass per output line. The half-open range excludesn, so the body runsntimes. - Build each line as left spaces, stars and right spaces joined with
+, thenprintit. Swift lets a line end in+and continue on the next. - Update the counters after printing. While
i < n / 2the rhombus is still widening. The middle line (i == n / 2) already falls into theelsebranch, so narrowing starts right after it. - Write the helper signature:
buildString(_ n: Int, _ character: String) -> String. The underscores remove the argument labels, so calls readbuildString(spaces, " "). - Fill the helper: a
var strstarts empty, a loop whose variable is_(it only counts) appendscharacterwith+=, and the method returnsstr.
The solution in Swift
class Solution {
func buildString(_ n: Int, _ character: String) -> String {
var str = ""
for _ in 0..<n {
str += character
}
return str
}
func printRhombus(_ n: Int) {
var stars = 1
var spaces = n / 2
for i in 0..<n {
let line = buildString(spaces, " ") +
buildString(stars, "*") +
buildString(spaces, " ")
print(line)
if i < n / 2 {
stars += 2
spaces -= 1
} else {
stars -= 2
spaces += 1
}
}
}
}
Swift details worth knowing:
0..<nversus0...n. The first excludesn; the second includes it and would print one line too many.for _ in. When the loop variable is unused,_says so and avoids a warning.- Strings are values.
str += characterchanges the localvar stronly; the caller's string is never touched. - Integer division.
5 / 2is 2 because both operands areInt. With an evennthe shape would be off-centre, which is why the problem promises an odd one. - Methods call each other by name. Inside
Solution,printRhombuscallsbuildStringdirectly; noself.is needed.
Why the counters work
It helps to check the invariant instead of trusting the picture. A line is correct when it is exactly n characters wide, and the width is spaces + stars + spaces. Before the loop, that is n / 2 + 1 + n / 2, which equals n for odd n. Each update adds 2 to one term and removes 1 from each of the other two, so the total never changes. The same argument covers the second half, with the signs swapped.
The turning point also follows from the numbers. The widest line has n stars and no spaces, and it comes after n / 2 widening steps, that is, on line i = n / 2. After the update on that line the counters would go to n + 2 stars, which can't be printed, so the branch condition must send that line to the shrinking side. That is exactly what i < n / 2 does.
Walking through n = 5
Before the loop: stars = 1, spaces = 2. Line 0 prints 2 spaces, 1 star and 2 spaces; the counters become 3 and 1. Line 1 prints 1 space, 3 stars and 1 space; the counters become 5 and 0. Line 2 is five stars and no spaces. Since 2 < 2 is false, the counters go back to 3 and 1, and lines 3 and 4 mirror lines 1 and 0.
Complexity
Time: O(n²). There are n lines and each is built from n characters in total, so the program does about n * n character appends.
Space: O(n). Only one line is held at a time.
Edge cases and common mistakes
n = 1.spacesstarts at 0, so one line, a single*, is printed. The counters are updated afterwards but never used again.n = 3. The output is*,***and*, three lines of three characters.- Forgetting the right-hand spaces. The line then ends right after the stars and is shorter than
n, so the output no longer matches. - Changing direction one line late or early. Using
i <= n / 2would widen the rhombus once more after the middle line. Forn = 5the next line would want 7 stars and-1spaces, and0..<-1is an invalid range in Swift, so the program crashes at run time instead of printing a wrong line. - Changing
starsby 1. Each side gains a star, so the total changes by 2.
Testing
printRhombus(5)prints the five lines shown above.printRhombus(3)prints*,***,*.printRhombus(1)prints*.
