Star diamond

Medium TimeO(n²) SpaceO(n²)

Given a half-height n, return a diamond of stars as an array of 2n − 1 strings. The first n rows widen from a single * to 2n − 1 stars, each centred behind its own padding, and the rows after them narrow back to a single star. The widest row belongs to both halves and appears exactly once.

Examples

Example 1

Input
n = 4
Output
   *
  ***
 *****
*******
 *****
  ***
   *
[" *"," ***"," *****","*******"," *****"," ***"," *"]
Four rows up to seven stars and three back down — seven rows, not eight.

Example 2

Input
n = 2
Output
 *
***
 *
[" *","***"," *"]
Three rows, and the shared three-star row is written once.

The Code

function diamond(n) {
  const rows = [];
  function addRow(stars, spaces) {
    let line = "";
    for (let i = 0; i < spaces; i++) line += " ";
    for (let i = 0; i < stars; i++) line += "*";
    rows.push(line);
  }
  for (let row = 1; row <= n; row++) {
    addRow(row * 2 - 1, n - row);
  }
  for (let row = n - 1; row >= 1; row--) {
    addRow(row * 2 - 1, n - row);
  }
  return rows;
}
diamond(4);
Done

The first 22 calls, of 67. This one does not fit on a page.

Step through diamond(4) call by call

Explanation

A diamond is a pyramid and its reflection. The two share their widest row, so it is written once and the diamond comes to 2n − 1 rows rather than 2n. Each space is drawn as · in the rows below.

  1. 1

    row is 1 in the first loop, and addRow(row * 2 - 1, n - row) is handed 1 star and 3 spaces. The helper lays the spaces down first, then the stars, and pushes the line onto rows.

    ···*
    0

    stars=1spaces=3

    rows.push("···*")

  2. 2

    row is 2, so the call becomes addRow(3, 2): two more stars and one space fewer, exactly as the pyramid widens.

    ···*
    0
    ··***
    1

    stars=3spaces=2

    rows.push("··***")

  3. 3

    row is 3 — addRow(5, 1).

    ···*
    0
    ··***
    1
    ·*****
    2

    stars=5spaces=1

    rows.push("·*****")

  4. 4

    row is 4, which is n, so addRow(7, 0) lays down the widest row with no padding in front of it. row++ then fails row <= n and the first loop is done.

    ···*
    0
    ··***
    1
    ·*****
    2
    *******
    3

    stars=7spaces=0

    rows.push("*******")

  5. 5

    The second loop opens at n - 1, which is 3 and not 4. Opening at n would call addRow(7, 0) again and the diamond would carry two widest rows.

    ···*
    0
    ··***
    1
    ·*****
    2
    *******
    3
    ·*****
    4

    row=3rows.length=4

    rows.push("·*****")

  6. 6

    row counts down through 2 and 1, calling the same helper with the same arguments the first loop used, so the rows come back out in reverse. At 0 it fails row >= 1 and the seven strings are returned.

    ···*
    0
    ··***
    1
    ·*****
    2
    *******
    3
    ·*****
    4
    ··***
    5
    ···*
    6

    row=2 then 1rows.length=5

    return rows → 7 rows