Pattern 13
Java source ↗ Edit this article ↗
Jump to code:
Problem
Given a positive integer n, print the increasing number triangle: n rows where row i (counting from 1) contains i numbers, and the numbers keep counting up across rows without ever restarting. Row 1 holds 1, row 2 holds 2 3, row 3 holds 4 5 6, and so on. Numbers in a row are separated by single spaces.
Constraints: 1 ≤ n ≤ 1000 is plenty for a printing exercise; the last number printed is n(n+1)/2, so for n = 1000 it is 500500.
Example 1
n = 4
1
2 3
4 5 6
7 8 9 10
Four rows, ten numbers in total, each row one number longer than the last.
Example 2
n = 5
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
The fifth row starts at 11 because the first four rows used up 1 + 2 + 3 + 4 = 10 numbers.
Reading the pattern
Two things describe this pattern completely:
- Shape. Row
ihasientries. The shape is a right-angled triangle, the same as the plain star triangle, so the loop skeleton is the familiarfor i in 1..n, for j in 1..i. - Content. The entries are consecutive integers that never reset. Row
itherefore starts right after the total number of entries in rows1 .. i-1, which is the triangular numberT(i-1) = (i-1)i/2.
Those two observations lead to two different programs. The first keeps a running counter and never thinks about where a row starts. The second computes the starting number of each row directly from i, which makes every row independent of the ones before it and lets you answer “what is the 3rd number of row 100?” in constant time.
Both methods below return the whole picture as a single String with one row per line. This makes the output testable: main compares it to expected strings, checks structural properties for n up to 30, and only then prints it.
Approach 1: One running counter
Intuition. Treat the output as a single stream of integers 1, 2, 3, ... that is cut into rows of growing length. Keep one variable next, and every time you print a number, increment it. The nested loops only control the shape; the counter controls the content, and because it lives outside both loops it is never reset.
Algorithm.
- Set
next = 1. - For
ifrom1ton: - For
jfrom1toi: ifj > 1append a space, then appendnextand increment it. - End the row with a newline.
static String counter(int n) {
StringBuilder sb = new StringBuilder();
int next = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
if (j > 1) sb.append(' ');
sb.append(next++);
}
sb.append('\n');
}
return sb.toString();
}
Complexity. Time O(n^2): there are n(n+1)/2 numbers, each appended in constant time (the number of digits is bounded by a small constant for any realistic n). Space O(n^2) for the returned string, which is the size of the output; only one extra int otherwise.
The if (j > 1) guard puts a separator between numbers rather than after each one, which avoids trailing spaces. Trailing whitespace is invisible but makes string comparisons in tests fail, so it is worth avoiding from the start.
Approach 2: Compute each row’s first number
Intuition. Rows 1 .. i-1 contain 1 + 2 + ... + (i-1) = i(i-1)/2 numbers. Row i therefore begins with i(i-1)/2 + 1 and continues for i steps. With that formula each row can be produced on its own, in any order, or even in parallel, and a single entry can be located without generating anything else.
Algorithm.
- For
ifrom1ton: letfirst = i(i-1)/2 + 1. - For
jfrom0toi-1: ifj > 0append a space, then appendfirst + j. - End the row with a newline.
static String formula(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= n; i++) {
long first = (long) i * (i - 1) / 2 + 1; // T(i-1) + 1
for (int j = 0; j < i; j++) {
if (j > 0) sb.append(' ');
sb.append(first + j);
}
sb.append('\n');
}
return sb.toString();
}
The same formula gives the value at any position directly:
static long valueAt(int r, int c) {
return (long) r * (r - 1) / 2 + c;
}
valueAt(r, c) is the c-th number (1-based) of row r. For instance valueAt(4, 2) = 6 + 2 = 8, and indeed row 4 is 7 8 9 10.
Dry run for n = 5:
| i | T(i-1) | first | row |
|---|---|---|---|
| 1 | 0 | 1 | 1 |
| 2 | 1 | 2 | 2 3 |
| 3 | 3 | 4 | 4 5 6 |
| 4 | 6 | 7 | 7 8 9 10 |
| 5 | 10 | 11 | 11 12 13 14 15 |
Complexity. Time O(n^2) to build the triangle, O(1) for valueAt. Space O(n^2) for the output string.
Why long? i * (i - 1) is computed before the division, and for i around 50 000 it already exceeds 2^31. Casting the first factor to long makes the whole product a long multiplication. The test valueAt(100000, 1) == 4999950001L would silently return a wrong value with int arithmetic. Note also that i(i-1) is always even, so the integer division is exact.
Edge cases and pitfalls
n = 0. No rows, empty string. Both methods handle it because their outer loop does not execute.n = 1. A single row containing1. In the formula approach,T(0) = 0, sofirst = 1, as required.- Resetting the counter. Declaring
int next = 1inside the outer loop restarts every row at 1 and prints the number pyramid1 / 1 2 / 1 2 3, which is a different pattern. The counter must live outside both loops. - Trailing spaces. Appending
" "after every number leaves a trailing space on each row. Use thej > 1(orj > 0) guard, orString.join. - Overflow in the formula.
i * (i - 1)overflowsintwheniis about46 341or more. Uselong, as shown, for any closed-form index arithmetic. - Multi-digit alignment. Once numbers reach two digits (from
10onwards) the rows are no longer visually aligned column by column. That is expected; the pattern is defined by the sequence, not by alignment. If alignment matters, pad each number to the width of the largest one. - Verifying correctness. The tests do not only compare against fixed strings; they also re-parse each row, check the token count equals the row number, and verify the tokens form the unbroken sequence
1, 2, 3, ...ending atn(n+1)/2. That kind of structural check catches off-by-one errors for everyn, not just the ones you wrote expectations for.
Related problems
- Pattern 12 also prints numbers but restarts at 1 in every row and mirrors them.
- Pattern 14 has the same triangular shape with letters instead of a running count.
- Pattern 16 keeps the triangle but repeats one symbol per row.
- Pattern 22 is the next step in “compute the cell from its coordinates”: there the value depends on both the row and the column.