Topics › Basics › Patterns

Pattern 15

Easy TUF ID 407 A2Z

Problem

Given a positive integer n, print the reverse letter triangle: n rows where the first row contains the first n capital letters A B C ... separated by single spaces, and each following row drops the last letter, until the final row is just A.

Constraints: 1 ≤ n ≤ 26, because there are 26 letters.

Example 1

n = 3
A B C
A B
A

Each row is the previous row without its last letter.

Example 2

n = 5
A B C D E
A B C D
A B C
A B
A

Five rows, the first with five letters, the last with one.

Reading the pattern

Row i (1-based) contains n - i + 1 letters, always starting at A. So the shape is an inverted right-angled triangle, and the content in column j (0-based) is (char) ('A' + j) just like the increasing version. The only difference from the growing triangle is the inner loop bound: it is n - i + 1 instead of i.

There is a second way to see it. The first row is the longest; every later row is the one above with two characters chopped off the end (a space and a letter). If you keep the current row in a mutable buffer, printing the pattern is “print, shrink by two, repeat”. This viewpoint avoids recomputing the letters of each row and is the natural way to think about patterns whose rows are suffix- or prefix-related.

Both approaches build the whole output as one String, one row per line, so main can compare against expected strings and structural properties before printing.

Approach 1: Nested loops with a shrinking bound

Intuition. Same skeleton as any triangle: an outer loop over rows and an inner loop over columns. Compute the number of letters of this row first, letters = n - i + 1, and let the inner loop run that many times. Prefix every letter except the first with a space.

Algorithm.

  1. For i from 1 to n: let letters = n - i + 1.
  2. For j from 0 to letters - 1: if j > 0 append a space; append (char) ('A' + j).
  3. End the row with a newline.
static String nestedLoops(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        int letters = n - i + 1;
        for (int j = 0; j < letters; j++) {
            if (j > 0) sb.append(' ');
            sb.append((char) ('A' + j));
        }
        sb.append('\n');
    }
    return sb.toString();
}

Complexity. Time O(n^2): n + (n-1) + ... + 1 = n(n+1)/2 letters plus the spaces between them. Space O(n^2) for the output; nothing else grows with n.

Approach 2: Build the first row and shrink it

Intuition. The first row, A B C ... with n letters, is the only one that needs letters computed. Every subsequent row is obtained by deleting its last two characters: the final letter and the space before it. StringBuilder.setLength(len - 2) does that deletion in O(1), since it just moves the end marker. Append the buffer, shrink, repeat.

Algorithm.

  1. Build row = A B ... with n letters (length 2n - 1).
  2. For i from 1 to n: append row and a newline; if row has at least two characters, drop the last two.
static String shrinking(int n) {
    StringBuilder row = new StringBuilder();           // "A B C ... " with n letters
    for (int j = 0; j < n; j++) {
        if (j > 0) row.append(' ');
        row.append((char) ('A' + j));
    }
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        sb.append(row).append('\n');
        if (row.length() >= 2) row.setLength(row.length() - 2);   // drop " X"
    }
    return sb.toString();
}

Dry run for n = 4:

i row before printing printed row after shrink
1 A B C D A B C D A B C
2 A B C A B C A B
3 A B A B A
4 A A A (length 1, no shrink)

Complexity. Time O(n^2): building the first row is O(n), each append(row) copies the current row, and the copies total (2n-1) + (2n-3) + ... + 1 = n^2 characters. Space O(n^2) for the output plus O(n) for the working row.

Why remove two characters? With single-space separators each letter after the first occupies two characters (" X"). Removing one character would leave a trailing space on the next row; removing three would eat a letter too many. The guard row.length() >= 2 protects the last iteration, where the row is just A and setLength(-1) would throw.

Edge cases and pitfalls