Pattern 6
Java source ↗ Edit this article ↗
Jump to code:
Problem
Given an integer n, print an inverted numbered right pyramid: n rows, where the first row is 1 2 ... n, the second is 1 2 ... n-1, and so on down to a last row containing just 1. Numbers in a row are separated by single spaces.
Output format: every row ends with a newline, one space between numbers, no trailing space, and multi-digit numbers printed in full. n = 0 prints nothing.
Constraints: 0 ≤ n ≤ 100 is typical.
Example 1
n = 4
1 2 3 4
1 2 3
1 2
1
Row i (0-based) counts from 1 to n - i.
Example 2
n = 2
1 2
1
Two rows: the full count and then the single 1.
Shape and content, separately
Two earlier patterns combine here. The shape is the inverted triangle: row i (0-based) has n - i cells, so the inner bound decreases with the row. The content is the counting pyramid: the cell in column j (1-based) holds the value j. Once you separate the two questions, the loops write themselves: outer i from 0 to n - 1, inner j from 1 to n - i, body prints j.
As with every number pattern, keep values as int and let StringBuilder.append(int) or Integer.toString format them. Converting to char breaks at 10.
All approaches return the pattern as a String so the tests can compare it to expected literals.
Approach 1: Nested loops
Intuition. The inner counter is both the loop control and the value printed. Its upper bound n - i shrinks by one per row. The separator goes before every number except the first.
Algorithm.
- For
ifrom0ton - 1: - For
jfrom1ton - i: ifj > 1append a space; append the numberj. - Append
\n. - Return the string.
static String nestedLoops(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
for (int j = 1; j <= n - i; j++) {
if (j > 1) sb.append(' ');
sb.append(j);
}
sb.append('\n');
}
return sb.toString();
}
Complexity. Time O(n^2): n(n+1)/2 numbers are written. Space O(n^2) for the output, O(1) extra.
Verify the two boundary rows. For i = 0 the inner loop runs j = 1..n and writes the full count. For i = n - 1 the bound is n - (n - 1) = 1, so the loop runs once and writes "1". If your last row is empty, the bound was n - i - 1; if your first row has n + 1 entries, the bound was n - i + 1 with a 0-based i. Checking the first and last row is the fastest way to confirm a shrinking bound.
Approach 2: Build the upright rows, emit them in reverse
Intuition. The rows of this pattern are exactly the rows of the upright counting pyramid ("1", "1 2", "1 2 3", …) listed from longest to shortest. And those upright rows are easy to produce incrementally: each one is the previous one with " k" appended. So grow a row buffer, snapshot it into a list after every extension, and then walk the list backwards. No reversal utility is needed; a descending index does it.
Algorithm.
- Keep a
rowbuilder and arowslist. - For
kfrom1ton: ifk > 1append a space; appendk; addrow.toString()torows. - For
ifromrows.size() - 1down to0: appendrows.get(i)and\n.
static String reversedRows(int n) {
List<String> rows = new ArrayList<>();
StringBuilder row = new StringBuilder();
for (int i = 1; i <= n; i++) {
if (i > 1) row.append(' ');
row.append(i);
rows.add(row.toString());
}
StringBuilder out = new StringBuilder();
for (int i = rows.size() - 1; i >= 0; i--) out.append(rows.get(i)).append('\n');
return out.toString();
}
Dry run for n = 3:
| k | row after extension |
rows |
|---|---|---|
| 1 | "1" |
["1"] |
| 2 | "1 2" |
["1", "1 2"] |
| 3 | "1 2 3" |
["1", "1 2", "1 2 3"] |
Walking backwards: "1 2 3\n1 2\n1\n".
Complexity. Time O(n^2); row.toString() copies O(k) characters at step k. Space O(n^2) for the list, which holds the whole pattern once, plus the output.
Approach 3: Stream over decreasing row lengths
Intuition. Describe the row lengths as the sequence n, n-1, ..., 1. IntStream.iterate(n, len -> len >= 1, len -> len - 1) generates exactly that: start at n, continue while the value is at least 1, step by -1. Each length maps to the row "1 2 ... len", built by an inner IntStream.rangeClosed(1, len) joined with spaces. The code states the pattern’s definition almost word for word.
Algorithm.
IntStream.iterate(n, len -> len >= 1, len -> len - 1)for the lengths.- For each
len, join1..lenas strings with" ", then add\n. Collectors.joining()concatenates the rows.
static String streams(int n) {
return IntStream.iterate(n, len -> len >= 1, len -> len - 1)
.mapToObj(len -> IntStream.rangeClosed(1, len)
.mapToObj(j -> Integer.toString(j))
.collect(Collectors.joining(" ")) + "\n")
.collect(Collectors.joining());
}
Complexity. Time O(n^2), space O(n) extra for one row at a time. For n = 0 the predicate 0 >= 1 fails immediately, the stream is empty, and the result is "".
The three-argument IntStream.iterate was added in Java 9; it is the stream equivalent of a classic for loop with a start value, a continuation test and a step.
Edge cases and pitfalls
n = 0. Every approach returns"".n = 1. Just"1\n".- Two-digit numbers. For
n = 11the first row is1 2 3 4 5 6 7 8 9 10 11, and the tests assert exactly that prefix. Do not assume one character per cell. - Wrong inner bound. With a 0-based row index the bound is
n - i; with 1-based rows it isn - i + 1. Mixing the two conventions produces either an empty last row or an extra cell on every row. charversusint.sb.append((char) ('0' + j))only works up to 9. Append theintdirectly.- Method references on
IntStream.mapToObj(Integer::toString)is ambiguous and fails to compile; writej -> Integer.toString(j). - Trailing space. Put the separator before every number except the first, or let
Collectors.joining(" ")do it. printlnversusprint. The returned string already ends with\n.