Topics › Basics › Build-up Logical Thinking

Easy and Medium

Easy TUF ID 1216 A2Z

What this covers

“Build-up logical thinking” on the sheet means pattern printing: given n, print a shape made of stars, numbers or spaces. The shapes are not useful in themselves. What they train is the ability to look at a two-dimensional output and turn it into two nested loops with the right bounds, which is the same skill you need later for matrices, dynamic-programming tables and grid problems. This article covers the easy and medium patterns (the first eleven on the sheet) and, more importantly, the fixed procedure that solves all of them. The hard patterns, which add mirrored halves, running counters and hollow interiors, are in the companion article.

Every pattern below is built into a String whose lines end in \n, so the Java file can assert exact output for small n; a program for a judge would print the same string with one System.out.print.

The four questions

For any pattern, answer these in order:

  1. How many rows? Usually n, sometimes 2n - 1 or 2n. The outer loop runs once per row.
  2. What is on row i? Describe it as segments: some spaces, then some symbols. Each segment is an inner loop (or a repeat).
  3. How does each segment’s length depend on i and n? Write the formula. Checking it on the first row, the last row and one in the middle catches most mistakes.
  4. Where do the line breaks go? After each row, outside the inner loops.

The square and the right triangle differ only in the answer to question 3.

Patterns 1 and 2: square and right triangle

In the square, every row has n stars. In the triangle, row i has i stars, so the inner bound becomes i.

static String square(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) sb.append('*');
        sb.append('\n');
    }
    return sb.toString();
}
static String rightTriangle(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) sb.append('*');
        sb.append('\n');
    }
    return sb.toString();
}

Both use 1-based row numbers because the formulas read more naturally that way (i stars on row i); 0-based works equally well as long as the formulas are adjusted.

Patterns 3 and 4: numbers instead of stars

The shape is still the right triangle. What changes is the symbol: in pattern 3 the j-th entry of a row is j itself; in pattern 4 every entry on row i is i. Numbers are separated by single spaces, and the if (j > 1) guard puts a separator before every entry except the first, so no row ends in a trailing space.

static String numberTriangle(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            if (j > 1) sb.append(' ');
            sb.append(j);
        }
        sb.append('\n');
    }
    return sb.toString();
}
static String repeatedNumberTriangle(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            if (j > 1) sb.append(' ');
            sb.append(i);
        }
        sb.append('\n');
    }
    return sb.toString();
}

The only difference between the two methods is sb.append(j) versus sb.append(i). Which loop variable to print is question 2 in disguise: “what is on row i at position j?”

Patterns 5 and 6: inverted triangles

To flip a triangle upside down, row i must have what row n - i + 1 had before. Substituting into the formulas: i stars becomes n - i + 1 stars. Check: row 1 has n, row n has 1.

static String invertedTriangle(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n - i + 1; j++) sb.append('*');
        sb.append('\n');
    }
    return sb.toString();
}
static String invertedNumberTriangle(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n - i + 1; j++) {
            if (j > 1) sb.append(' ');
            sb.append(j);
        }
        sb.append('\n');
    }
    return sb.toString();
}

This substitution trick, “replace i by n - i + 1”, is worth remembering: it turns any top-heavy pattern into its bottom-heavy twin without new reasoning.

Patterns 7, 8 and 9: pyramids and the diamond

A centred pyramid introduces a second segment per row: leading spaces that shrink as the stars grow. On row i of a pyramid with n rows there are n - i spaces followed by 2i - 1 stars, so the last row has 0 spaces and 2n - 1 stars, which is the full width. String.repeat expresses a segment in one call and keeps the row structure visible.

static String pyramid(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        sb.append(" ".repeat(n - i)).append("*".repeat(2 * i - 1)).append('\n');
    }
    return sb.toString();
}

The inverted pyramid applies the flip substitution to both segments: i - 1 spaces and 2(n - i) + 1 stars.

static String invertedPyramid(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        sb.append(" ".repeat(i - 1)).append("*".repeat(2 * (n - i) + 1)).append('\n');
    }
    return sb.toString();
}

A diamond is a pyramid with an inverted pyramid underneath, 2n rows in total. Rather than deriving a single formula with a case split, reuse the two methods:

static String diamond(int n) {
    return pyramid(n) + invertedPyramid(n);
}

Composition is a legitimate pattern-printing technique: if a shape is visibly two known shapes stacked, print them in sequence.

Pattern 10: the half diamond

Star counts rise 1, 2, ..., n and then fall n - 1, ..., 1, giving 2n - 1 rows. The row index i runs over all of them, and a single expression maps it to the number of stars: i while i <= n, then 2n - i. Check: i = n gives n either way, i = 2n - 1 gives 1.

static String halfDiamond(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= 2 * n - 1; i++) {
        int stars = i <= n ? i : 2 * n - i;
        sb.append("*".repeat(stars)).append('\n');
    }
    return sb.toString();
}

This “fold the row index at n” idea is the engine behind the butterfly and other symmetric hard patterns.

Pattern 11: the binary triangle

Row i starts with 1 when i is odd and 0 when even, then alternates. Keep a bit variable: initialise it to i % 2 at the start of the row and flip it with bit = 1 - bit after each print. The flip is a tiny piece of state carried across the inner loop, which is new compared with the patterns above.

static String binaryTriangle(int n) {
    StringBuilder sb = new StringBuilder();
    for (int i = 1; i <= n; i++) {
        int bit = i % 2;
        for (int j = 1; j <= i; j++) {
            if (j > 1) sb.append(' ');
            sb.append(bit);
            bit = 1 - bit;
        }
        sb.append('\n');
    }
    return sb.toString();
}

An equivalent closed form is (i + j) % 2 for 1-based i and j; both are fine, but the explicit bit reads more like the description of the pattern.

Edge cases and pitfalls