Print Number Triangle in Java
Problem
Each row of a number triangle restarts its own count from 1, so row i always ends at the number i — the row number and the row's last value are the same thing.
Given a number of rows, print a left-aligned triangle where row i contains the numbers 1 through i.
Java Program
public class NumberTriangle {
public static void main(String[] args) {
int n = 5;
for (int i = 1; i <= n; i++) {
StringBuilder line = new StringBuilder();
for (int j = 1; j <= i; j++) {
if (j > 1) line.append(" ");
line.append(j); // resets to 1 at the start of every row
}
System.out.println(line);
}
}
}Output
Core Logic
Restarting a counter at 1 for every row, and running it up to that row's own number, prints each row's numbers independently of every other row.
- 1The outer loop runs
ifrom 1 ton, one iteration per row. - 2The inner loop runs
jfrom 1 toi, printingjat each step — so rowialways ends with the valueiitself. - 3Because
jis declared fresh inside the outer loop, it resets back to 1 at the start of every row. - 4Each row is joined with a single space between the numbers and printed as one line.
n = 5, row 3 prints 1 2 3 — three numbers, restarting from 1 — while row 5 prints 1 2 3 4 5.Key Point: The inner loop variable resetting to 1 every row is the whole idea here — the same loop shape as a star triangle, just printing the loop counter instead of a fixed character.
Why: The total count of numbers printed across every row is 1+2+...+n, proportional to n², and only the loop counters are kept.
Key Concepts
Approach 2: Java 8
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class NumberTriangleStream {
public static void main(String[] args) {
int n = 5;
IntStream.rangeClosed(1, n)
.mapToObj(i -> IntStream.rangeClosed(1, i)
.mapToObj(String::valueOf)
.collect(Collectors.joining(" ")))
.forEach(System.out::println);
}
}
Output
Core Logic
Mapping each row's column positions directly to their own values, instead of a fixed row-wide value, reproduces the counting-up sequence one row at a time.
- 1
IntStream.rangeClosed(1, n)generates one stream element per row. - 2For each row
i, an innerIntStream.rangeClosed(1, i)generates that row's own values,1throughi. - 3
.mapToObj(String::valueOf)converts each value to a String for joining. - 4
Collectors.joining(" ")joins that row's numbers beforeforEachprints it.
1, 2, 3, 4 directly and joins them into "1 2 3 4".Key Point: The inner stream is re-created fresh for every row, the same as the inner loop's counter resetting each time — nothing carries over from one row's stream to the next.
Why: The nested streams still produce one value per grid position across all rows, proportional to n², without collecting the full triangle.