Command Palette

Search for a command to run...

PHASE 2Beginner ~29 min· topic 9 of 10

Topic 2.9

Nested Loops and Patterns

In one line

A loop inside another loop runs its whole inner loop once for every iteration of the outer one. That's how you walk grids, compare every pair, and print patterns, and it's why the work grows as rows × columns (often n²).

Think of it like this

A clock. The minute hand goes all the way round, 60 steps, for each single step of the hour hand. In 12 hours the minute hand moves 12 × 60 = 720 times. Nested loops behave the same: the inner loop finishes all its rounds before the outer loop takes one step.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Nested loop
A loop placed inside the body of another loop.
Outer loop
The enclosing loop. It moves one step at a time.
Inner loop
The loop inside. It runs completely for every single step of the outer loop.
Row and column
Positions in a grid: rows go down, columns go across.
Pair
Two different elements taken together, like (3, 8). n items have n(n-1)/2 unordered pairs.
Time complexity
How the amount of work grows as the input grows. Two nested loops over n items usually mean n² work, written O(n²).
printf
A print method that formats values with a template, like %4d for 'an integer in a field 4 characters wide'.

Step by step

01Watch the inner loop restart

Print the counters to see the order. For each value of i, j starts again at 1 and runs all the way to 3. The inner body runs 2 × 3 = 6 times.

Main.javawhole filejava
for (int i = 1; i <= 2; i++) {
    for (int j = 1; j <= 3; j++) {
        System.out.println("i=" + i + " j=" + j);
    }
}
terminal
$ java Main.java
── expected output ──
i=1 j=1
i=1 j=2
i=1 j=3
i=2 j=1
i=2 j=2
i=2 j=3

02Rows and columns: a grid

To print a grid, the outer loop handles rows, the inner loop prints each column with print (no newline), and a println() after the inner loop finishes the row.

printf("%4d", x) prints x right-aligned in 4 characters, so the columns line up. %n is a platform-independent newline.

Main.javawhole filejava
for (int row = 1; row <= 3; row++) {
    for (int col = 1; col <= 4; col++) {
        System.out.printf("%4d", row * col);
    }
    System.out.println();
}
terminal
$ java Main.java
── expected output ──
1 2 3 4
2 4 6 8
3 6 9 12

03Patterns: turn the shape into a formula

Draw the shape, number the rows from 1, and write down for each row how many spaces and how many stars it has. Then find the rule.

For a pyramid of height 4: row 1 has 3 spaces and 1 star, row 2 has 2 spaces and 3 stars, row i has n - i spaces and 2 * i - 1 stars. Two inner loops, one per part, then println().

Main.javawhole filejava
int n = 4;
for (int i = 1; i <= n; i++) {
    for (int s = 0; s < n - i; s++) System.out.print(" ");
    for (int k = 0; k < 2 * i - 1; k++) System.out.print("*");
    System.out.println();
}
terminal
$ java Main.java
── expected output ──
*
***
*****
*******

04Inner bounds that depend on the outer variable

When the inner loop starts at i + 1, it visits every pair exactly once and never pairs an element with itself. For 4 items that's 6 pairs, not 16.

This 'every pair' loop is the brute-force solution to many interview questions (two-sum, closest pair, duplicates). The DSA course shows how hashing or sorting removes the inner loop.

Main.javawhole filejava
String[] team = {"Ana", "Bob", "Cy", "Dee"};
for (int i = 0; i < team.length; i++) {
    for (int j = i + 1; j < team.length; j++) {
        System.out.println(team[i] + " vs " + team[j]);
    }
}   // 6 matches
Inner bounds that depend on the outer variablediagram
Rendering diagram…

05How fast does the work grow?

Count the inner body runs. A full n × n nest runs n² times; the pair loop runs n(n-1)/2 times, about half, but still grows with n². Three nested loops would be n³.

At n = 1,000, n² is a million (fast); at n = 100,000 it's ten billion (seconds to minutes). That's why nested loops are fine for small inputs and the first thing to remove for big ones.

06The two classic nested-loop bugs

Wrong variable in the inner header: for (int j = 0; j < 3; i++) increments i, so j never changes and the inner loop never ends (or i races past the array and throws).

Inner counter not reset: declaring int j = 0; once, outside the outer loop, and writing for (; j < 3; j++) means j is already 3 when the second row starts, so only the first row is printed. Declare each counter in its own header and both bugs become hard to write.

Main.javawhole filejava
int j = 0;
for (int i = 1; i <= 3; i++) {
    for (; j < 3; j++) {          // j is never reset
        System.out.print("*");
    }
    System.out.println(" row " + i);
}
terminal
$ java Main.java
── expected output ──
*** row 1
row 2
row 3

Try it yourself

  1. 1

    Flip the triangle

    In 'Four classic patterns', make the right triangle upside down (4 stars first, 1 last) by changing only the inner loop's bound. Hint: row i should print n - i + 1 stars.

  2. 2

    Predict the count

    Add n = 2000 to sizes in 'Counting the work'. Predict full and pairs before running (4,000,000 and 1,999,000).

  3. 3

    Make a diamond

    Below the pyramid, add a second loop that counts i down from n - 1 to 1 with the same body. Together they print a diamond.

Code & diagrams

Multiplication table New tab
Sign in to run this example in your browser.

Expected output

   |   1   2   3   4   5
---+--------------------
 1 |   1   2   3   4   5
 2 |   2   4   6   8  10
 3 |   3   6   9  12  15
 4 |   4   8  12  16  20
 5 |   5  10  15  20  25
Four classic patterns New tab
Sign in to run this example in your browser.

Expected output

Right triangle:
*
**
***
****
Pyramid:
   *
  ***
 *****
*******
Floyd's triangle:
1
2 3
4 5 6
7 8 9 10
Hollow square:
####
#..#
#..#
####
Counting the work: n² vs pairs New tab

Ten times more input means a hundred times more work: the signature of O(n²).

Sign in to run this example in your browser.

Expected output

n=10  full=100  pairs=45
n=100  full=10000  pairs=4950
n=1000  full=1000000  pairs=499500
break only leaves the inner loop New tab
Sign in to run this example in your browser.

Expected output

i=1 j=1
i=2 j=1
i=3 j=1
The outer loop still ran 3 times

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Declare the inner counter outside

Declare int j = 0; before the outer loop and use for (; j < 3; j++) inside.

Main.javawhole filejava
public class Main {
    public static void main(String[] args) {
        int j = 0;
        for (int i = 1; i <= 3; i++) {
            for (; j < 3; j++) {
                System.out.print("*");
            }
            System.out.println(" row " + i);
        }
    }
}
terminal
$ java Main.java
── what you'll see ──
*** row 1
row 2
row 3

Break #2

Increment the wrong counter

Write for (int j = 0; j < 3; i++) in the inner loop of a loop over an array with arr[i] in the body.

Main.javawhole filejava
public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < 3; i++) {
                System.out.println(arr[i]);
            }
        }
    }
}
terminal
$ javac Main.java && java Main
── what you'll see ──
1
2
3
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at Main.main(Main.java:6)

Myth vs fact

Myth

Two nested loops always mean n² work.

Fact

Only if both run about n times. An inner loop with a fixed bound (say 26 letters) or one that shrinks quickly can make the total linear.

Myth

break in the inner loop stops everything.

Fact

It stops only the innermost loop. The outer loop carries on with its next iteration.

Myth

Pattern questions need a special trick per shape.

Fact

They all reduce to: for row i, how many spaces and how many symbols? Write the table, find the formula.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Loop order matters for memory. A Java int[][] is an array of row arrays; iterating for row { for col } reads each row sequentially (cache-friendly), while for col { for row } jumps between separate arrays on every step and can be several times slower for large grids.

  • ▸

    The JIT can hoist loop-invariant work out of the inner loop and remove bounds checks, but only when the inner loop is a simple counted loop. Calling a method in the inner condition (j < list.size()) is usually fine after inlining; reading a non-final field may block hoisting.

  • ▸

    Printing character by character with System.out.print is slow: System.out is a synchronized PrintStream, and each call takes a lock and may flush. For big outputs, build each line with a StringBuilder (or "*".repeat(k), Java 11) and print once per line.

  • ▸

    Interviewers use nested loops to probe complexity: be ready to state the exact count (like n(n-1)/2) and then to remove a level with a hash set, sorting plus two pointers, or prefix sums.

Remember this

  1. 1

    With an outer loop of R iterations and an inner loop of C, the inner body runs R × C times. For a square of size n that's n², so doubling n makes the work four times bigger. This is your first taste of time complexity, which the DSA course (/dsa) builds on.

  2. 2

    The usual reading for printing: the outer loop picks the row, the inner loop prints the columns of that row, and a println() after the inner loop ends the line. Almost every pattern question is solved by working out, for row i, how many spaces and how many symbols to print.

  3. 3

    The inner loop's bounds may depend on the outer variable: for (int j = 0; j <= i; j++) prints a growing triangle, and for (int j = i + 1; j < n; j++) visits each pair once (n(n-1)/2 times instead of n²).

  4. 4

    Use different names for each level (i/j, or row/col) and declare each counter in its own loop header. Two classic bugs: incrementing the wrong variable in the inner header (j < n; i++), and declaring the inner counter outside the outer loop so it never resets.

  5. 5

    A plain break or continue only affects the innermost loop. To stop both loops, use a labelled break (Topic 2.8) or a return from a method.

  6. 6

    Nested loops over a 2D array (Topic 3.9) should normally put the row index outside and the column inside. Java stores each row as a separate array, so walking along a row touches neighbouring memory, which the CPU cache rewards.

Explain it without notes

01

If the outer loop runs 5 times and the inner loop runs 4 times, how many times does the inner body run, and why?

02

How do you approach printing a pattern such as a pyramid?

03

Why does the inner loop in for (int j = i + 1; j < n; j++) produce each pair once, and how many iterations does it do?

04

Why should the inner counter be declared in the inner loop's header?

Practice

01

Print an inverted right triangle of height 4 using #.

02

Print the numbers 1 to 3 in a 3 × 3 grid where each row repeats its row number (1 1 1, 2 2 2, 3 3 3).

03

Given int[] a = {2, 7, 4, 7, 2, 9}, use nested loops to print every pair of positions that hold equal values.

Trade-offs

  • ↔

    Nested loops are the simplest correct solution for grids and pairs, but O(n²) work becomes too slow somewhere between thousands and millions of items; then use hashing, sorting or a smarter algorithm.

  • ↔

    Printing patterns character by character is easy to reason about; building each line with repeat or a StringBuilder is faster and shorter but hides the per-character logic beginners need to see.

Done when you can

  • Done when you can trace a nested loop and state how many times the inner body runs.

  • Done when you can print a triangle, pyramid and hollow square from a row/space/symbol table.

  • Done when you can write the every-pair loop with j = i + 1 and give its iteration count.

  • Done when you can spot an inner counter that isn't reset or a wrong variable in the inner header.

  • Done when you can explain why row-then-column order is faster for 2D arrays.