Pattern 16
Java source ↗ Edit this article ↗
Jump to code:
Problem
Given a positive integer n, print the alpha-ramp: n rows where row i (counting from 1) prints the i-th capital letter exactly i times, separated by single spaces. Row 1 is A, row 2 is B B, row 3 is C C C, and so on.
Constraints: 1 ≤ n ≤ 26, because there are 26 letters.
Example 1
n = 3
A
B B
C C C
Row i uses only one letter, the i-th one, repeated i times.
Example 2
n = 5
A
B B
C C C
D D D D
E E E E E
The letter changes with the row, not with the column.
Reading the pattern
Compare this with the increasing letter triangle A / A B / A B C. The shape is identical (i items in row i), but the content rule is flipped: there the letter depended on the column, here it depends on the row. Row i prints (char) ('A' + i - 1), and the inner loop merely repeats it.
That is the whole lesson of this pattern: before writing loops, decide which index each piece of content depends on. If it depends on the row only, compute it once per row, outside the inner loop. That is both faster to write and less error-prone than recomputing inside.
Because every row consists of one symbol repeated with a separator, there is also a one-line way to produce a row with the String.repeat method that Java has had since version 11. Both approaches below return the finished picture as a single String (newline after every row) so main can compare them with expected strings before printing.
Approach 1: Nested loops, letter fixed per row
Intuition. Outer loop over rows, inner loop over columns. Compute the row’s letter once with char arithmetic, then let the inner loop append it i times with a space before every copy except the first.
Algorithm.
- For
ifrom1ton: letch = (char) ('A' + i - 1). - For
jfrom0toi - 1: ifj > 0append a space; appendch. - End the row with a newline.
static String nestedLoops(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= n; i++) {
char ch = (char) ('A' + i - 1);
for (int j = 0; j < i; j++) {
if (j > 0) sb.append(' ');
sb.append(ch);
}
sb.append('\n');
}
return sb.toString();
}
Complexity. Time O(n^2): n(n+1)/2 letters and n(n-1)/2 spaces, each appended in O(1). Space O(n^2) for the output string; no other memory depends on n.
The cast (char) ('A' + i - 1) is evaluated once per row. Note the parentheses: 'A' + i - 1 is an int, and the cast applies to the whole expression. Writing (char) 'A' + i - 1 would cast 'A' alone (a no-op) and leave you with an int, which append would print as a number.
Approach 2: One repeat call per row
Intuition. (ch + " ") is the two-character string "C ". Repeating it i times gives "C C C ", and stripTrailing() removes the one trailing space. That expresses “this letter, i times, separated by spaces” in a single expression, with no inner loop to get wrong.
The ch + " " part deserves a second look. ch is a char and " " is a String; because one operand is a String, Java performs string concatenation and produces "C ". Had both operands been chars (ch + ' ') the result would have been an int sum of code points.
Algorithm.
- For
ifrom1ton: letch = (char) ('A' + i - 1). - Append
(ch + " ").repeat(i).stripTrailing()and a newline.
static String withRepeat(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= n; i++) {
char ch = (char) ('A' + i - 1);
sb.append((ch + " ").repeat(i).stripTrailing()).append('\n');
}
return sb.toString();
}
Dry run for n = 4:
| i | ch | (ch + " ").repeat(i) |
after stripTrailing |
|---|---|---|---|
| 1 | A |
"A " |
A |
| 2 | B |
"B B " |
B B |
| 3 | C |
"C C C " |
C C C |
| 4 | D |
"D D D D " |
D D D D |
Complexity. Time O(n^2): repeat(i) produces 2i characters and stripTrailing scans back over at most one of them, so each row costs O(i). Space O(n^2) for the output plus O(n) for the temporary row strings, which are garbage after each iteration.
Is this better than Approach 1? Not asymptotically. It is shorter and reads as a description of the row, which matters when the pattern is one piece of a bigger program. The loop version is what you write when you need to control each character, for instance to vary the separator. Knowing both lets you choose.
Edge cases and pitfalls
n = 0. Empty output; the outer loop does not execute in either method.n = 1. One row,A. In Approach 2,"A ".repeat(1)is"A ", andstripTrailingleavesA.- Letter from the wrong index. Using
'A' + j(the column) printsA / A B / A B C, which is a different pattern. Here the letter is'A' + i - 1, computed from the row. - The
- 1. Rows are 1-based in the description but code points start at'A'for row 1, so the offset isi - 1. Starting the loop ati = 0and using'A' + iis an equivalent alternative; just do not mix the two conventions. n > 26.'A' + 26is'['; the program runs but the output is no longer letters. Validate the input if it is not guaranteed.char + charis anint.ch + ' 'adds two code points and yields a number. Make sure one operand is aString(ch + " ") when you want concatenation.trimvsstripTrailing. Both remove the trailing space here.stripTrailingonly touches the end and understands Unicode whitespace;trimalso strips the front, which is harmless in this pattern but would destroy leading spaces in centred patterns.
Related problems
- Pattern 14 has the same shape with the letter depending on the column instead of the row.
- Pattern 15 inverts the triangle.
- Pattern 17 combines the row and column dependencies into a centred letter hill.
- Pattern 21 uses
String.repeatto build whole rows of a hollow rectangle.