2. Print A forward. When i = 5, range(base, base + 5) prints ABCDE; when i = 1, just A.
3. Newline. Bare print() after the inner loop starts the next shorter row.
Example 2 — Row Count Input
Read how many rows to print. Cap at 26 so letters stay in A–Z.
Python
raw = input("Enter the number of rows (max 26): ").strip()
try:
rows = int(raw)
except ValueError:
print("Please enter a whole number.")
raise SystemExit(1)
rows = max(1, min(rows, 26))
base = ord("A")
for i in range(rows, 0, -1):
for code in range(base, base + i):
print(chr(code), end="")
print()
Output (when user enters 4)
ABCD
ABC
AB
A
How It Works
1. Validate rows. Parse an integer, then clamp to 1..26.
2. Same shrinking core. Four rows start at ABCD and end at A.
Example 3 — letters[:i]
Slice the alphabet for each shrinking length — no inner letter loop.
Python
rows = 5
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i in range(rows, 0, -1):
print(letters[:i])
Output
ABCDE
ABCD
ABC
AB
A
How It Works
1. One slice.letters[:i] is the first i letters (ABCDE when i = 5).
2. Same shape. Identical output to Example 1 — keep the nested-loop version for exams that ask for ord/chr bounds.
Edge Cases & Pitfalls
Check these before calling the solution done.
grow not shrink
range(1, rows + 1)
That outer loop is Program 1. Keep range(rows, 0, -1) for the decreasing shape.
off-by-one
range(rows, -1, -1)
Including 0 makes an empty last row. Stop at 1 with range(rows, 0, -1).
newline early
Bare print() inside the inner loop
Use end="" for letters; call bare print() only after the ascending run.
rows > 26
Letter past Z
Cap rows at 26 so base + i - 1 stays in A–Z.
rows = 1
Single A
Output is just A — a good sanity check.
Bad input
Non-integer rows
Catch ValueError from int(...) before the outer loop.
Analysis
Time and Space Complexity
Program
Time
Extra space
Nested loops (Examples 1–2)
O(n²)
O(1)
Slice shortcut (Example 3)
O(n²)
O(n) per row for the slice string
There are n rows printing n+(n-1)+…+1 letters, so total work is n(n+1)/2.
Remember
Key Takeaways
Rule: for i = n..1, print A through the i-th letter.
Flip of Program 1: same ascending letters; only the outer loop direction changes.
Shortcut:letters[:i] inside a shrinking outer loop.
Next step: Program 6 keeps full width while the start letter moves toward E.
One line: for each length from n down to 1, print A forward that many letters.
Frequently Asked Questions
The outer loop walks i from rows down to 1, so the first row is longest. The inner loop prints letters from ord('A') through i characters: ABCDE, then ABCD, then ABC, and so on until A.
That range yields rows, rows-1, ..., 1 — exactly how many letters each row needs. Program 1 uses range(1, rows + 1) for the opposite (growing) shape.
print(chr(code), end="") stays on the same line. print() ends the current line. Letters use end=""; the row break uses print() after the inner loop.
Program 1 grows each row (A, AB, ABC). This pattern shrinks: the first row has rows letters from A, each next row drops the last letter. Only the outer loop direction changes — inner letter logic stays the same.
O(n²) where n is the number of rows. Total printed characters still equal n+(n-1)+...+1 = n(n+1)/2 — same triangular count as the increasing triangle.
Yes. Keep letters = "ABCDEFG..." and print(letters[:i]) inside for i in range(rows, 0, -1). Nested ord/chr loops teach the bounds; slicing is a compact shortcut.
Use try/except ValueError around int(input()), then clamp rows between 1 and 26 so letter codes stay within A–Z.
Letter codes walk past Z and print unexpected characters. Clamp to 26 for A–Z demos, or define a clear error/wrap policy.
🤔
Did you know?
Row i prints letters from A through the i-th letter, with i shrinking each row: ABCDE, ABCD, …, A. Total letters for n rows is still n(n+1)/2 — O(n²).