Shape Rule
only odd row widths
Row lengths are 7, 5, 3, 1 — each row prints 1 through i with no even-width lines.

The odd-length descending number triangle teaches how a custom outer-loop step (range(..., -2)) skips even row widths. This tutorial covers the shape rule, loop structure, a live preview, algorithm steps, worked Python examples, edge cases, and complexity.
only odd row widths
Row lengths are 7, 5, 3, 1 — each row prints 1 through i with no even-width lines.
Rows
for i in range(max_n, 0, -2): visits only odd row lengths from the top down.
1..i ascending
for j in range(1, i + 1): prints digits 1 through i on every row.
Same line / next line
Digits use print(j, end=""); end each row with print().
1–20 max
Pick an odd maximum and draw the odd-length descending triangle instantly in the browser.
Complexity
Total digit prints still = n(n+1)/2; extra memory stays O(1).
An odd-length descending number triangle prints ascending digits on each row, but only for odd row widths. With max_n = 7, the output is 1234567, 12345, 123, 1.
In Python you solve it with a descending outer loop that steps by 2: for i in range(max_n, 0, -2):, an inner loop for j in range(1, i + 1): that prints each digit, then print() ends each row.
It shows how changing the loop step creates entirely new shapes — not just different bounds.
range(..., -2) skips even row widths.
Inner loop always prints 1..i on every row.
print(j, end="") in the inner loop; print() after.
Follow Program 13; continue to Program 15 (binary triangle).
In short: for each odd row length i from max_n down to 1 stepping by 2, print 1..i with print(j, end=""), then call print().
Given a positive odd integer max_n (or adjusted to odd), print an odd-length descending number triangle: row length i prints digits 1 through i, with the outer loop using range(max_n, 0, -2).
# max_n = 7 (conceptual shape)
# 1234567
# 12345
# 123
# 1
for i in range(max_n, 0, -2):
for j in range(1, i + 1):
print(j, end="") # digits 1..i
print() # next row | Item | Type | Description |
|---|---|---|
max_n | int | Maximum (odd) row width — first row prints 1..max_n. |
| Printed output | text | Only odd-length rows; each prints ascending digits 1..i. |
for i from max_n down to 1 step -2:
for j from 1 to i:
print j (no newline)
print newline | Approach | Idea | Best for |
|---|---|---|
range(..., -2) outer loop | Skip even row widths | Learning and interviews |
range(..., -1) outer loop | Print every width (7, 6, 5, …, 1) | Full descending triangle comparison |
| Goal | Pattern |
|---|---|
| Walk odd row lengths | for i in range(max_n, 0, -2): |
Print 1..i | for j in range(1, i + 1): print(j, end="") |
| End the row | print() |
| Force odd max | if max_n % 2 == 0: max_n -= 1 |
| All widths variant | for i in range(max_n, 0, -1): (step by 1) |
| Program 13 variant | if i % 2 == 0 descending else ascending (zigzag) |
Same family of triangles — different outer-loop steps.
odd onlyPrints 7, 5, 3, 1 — skips even widths
all widthsPrints 7, 6, 5, 4, 3, 2, 1 — every row
ascendingAlways prints digits 1 through i on each row
step firstMaster step -2 before comparing with step -1
Reach for this pattern when teaching custom loop steps and skipped iterations.
Most Python pattern series start here before pyramids and diamonds.
Outer/inner bound practice with an immediate visual check.
Combine loops with input() for a flexible row count.
Compare Program 13 (zigzag) and Program 15 (binary triangle) next.
This is a console teaching pattern — not how you build modern app screens.
Key benefit: one small program that locks in nested loops, output sequencing, and O(n²) thinking.
Enter an odd maximum between 1 and 20 and draw the odd-length descending triangle in the browser.
Three complete Python programs — fixed maximum, configurable input(), and a step-by-1 comparison. Click View Output to reveal sample console results.
Print four odd-length rows starting from max_n = 7 with a step of -2.
max_n = 7Hard-coded height — ideal for first demos and screenshots.
for i in range(7, 0, -2):
for j in range(1, i + 1):
print(j, end="")
print() When i = 7, the inner loop prints 1234567. When i = 5, it prints 12345, and so on until i = 1 prints 1. The outer loop skips even lengths because of the step -2. print() after the inner loop starts the next row.
Let the user choose the maximum row width at runtime.
Read an odd maximum with input() and int() (wrap in try/except ValueError in real apps); if the user enters an even number, subtract 1.
max_n = int(input("Enter an odd maximum (e.g., 9): "))
if max_n % 2 == 0:
max_n -= 1
for i in range(max_n, 0, -2):
for j in range(1, i + 1):
print(j, end="")
print() Same nested-loop core as Example 1; max_n comes from input and is forced odd with if max_n % 2 == 0: max_n -= 1. Non-numeric input raises ValueError with bare int(input()) — use try/except for safer labs.
Same ascending inner loop, but outer loop steps by 1 to include every width.
range(..., -1))Print every row width from 7 down to 1 — includes even-length rows for comparison.
max_n = 7
for i in range(max_n, 0, -1):
for j in range(1, i + 1):
print(j, end="")
print() Changing the outer step from -2 to -1 includes every row width — even lengths like 123456 and 12 appear. Same inner loop; only the outer step changes the shape.
print() is built in; use input() when reading input. Set max_n (fixed or from input, forced odd if needed).
for i in range(max_n, 0, -2): picks odd row lengths only; inner loop prints 1..i.
for j in range(1, i + 1): prints ascending digits with print(j, end="") on every row.
print() ends the row so the next outer iteration starts fresh.
Total digit prints: 1+2+…+n = n(n+1)/2 — O(n²) time, O(1) extra memory.
max_n = 7Trace each outer-loop value of i and note the ascending digits printed on each odd-length row.
i | Step from prev | Inner j range | Printed row |
|---|---|---|---|
7 | start | 1..7 | 1234567 |
5 | -2 | 1..5 | 12345 |
3 | -2 | 1..3 | 123 |
1 | -2 | 1..1 | 1 |
Skipped even lengths: 6, 4, 2. Total digit prints: 7+5+3+1 = 16.
Where this tiny pattern (and its loop structure) shows up beyond the homework prompt.
Clearest visual proof that outer and inner bounds interact.
Example: change j <= i and watch the shape change.
Foundation for inverted, pyramid, diamond, and hollow variants.
Example: change range(..., -2) to range(..., -1) for a full descending triangle.
Practice print vs row newline without complex math.
Example: put print() inside the inner loop by mistake.
Swap digits for letters, stars, or spaced output once the loop works.
Example: print j + " " for spaced digits on each row.
Triangular totals make O(n²) concrete for beginners.
Example: count printed digits for n = 10 still → 55.
Pair the pattern with input() return checks and positive-row validation.
Example: reject max_n <= 0 and re-prompt.
Pro Tip: when an interviewer asks for patterns, explain the outer/inner roles first — then write the loops. The story matters as much as the code.
Why this pattern earns a permanent spot in beginner Python courses.
Wrong bounds show up immediately as a broken staircase.
Only loops and console output — no arrays or math libraries.
Invert, center, hollow, or change the fill character with small edits.
Streaming output needs no storage beyond loop counters.
Pro Tip: learn step -2 first; compare with step -1 to see how the loop step changes the whole shape.
Small habits that keep number-pattern code clean.
Use max_n (avoid shadowing builtin max) and keep i/j for row/column — or rename to row/col.
try/except ValueErrorWrap int(input()) in try/except ValueError so bad input does not leave max_n unset.
Only call print() after the inner loop finishes the row.
if max_n % 2 == 0: max_n -= 1 keeps the first row odd-length when reading input.
Trace max_n = 7 on paper before coding larger demos.
Pro Tip: if the output is a vertical list of single digits per line, you almost certainly put print() inside the inner loop.
Mistakes that commonly break odd-length descending number patterns.
Each digit lands on its own line — you get a column, not a triangle.
→ Use print(j, end="") for digits; print() only after the inner loop.
range(..., -1) prints every width; range(..., -2) starting from an even max_n skips the intended first row.
→ For odd-only rows, use for i in range(max_n, 0, -2) with odd max_n.
Omitting print() glues every digit onto one endless line.
→ Always end the row after the inner loop.
Letters or empty input raise ValueError with bare int(input()).
→ Catch ValueError and re-prompt on failure.
Switching to a 0-based outer loop without adjusting the stop value can drop the last row or print an empty first row.
→ Prefer range(max_n, 0, -2) with range(1, i + 1) for the digits.
Check these inputs before calling the solution done.
Output is just 1 on one line.
Outer loop never runs — print nothing or show a message.
max_n < 0Treat as invalid; re-prompt instead of silent empty output.
Output grows as n²/2 characters — fine for labs, noisy for huge n.
int(input()) raises ValueError — validate first.
Subtract 1 or prompt again — otherwise the first row may not match the odd-only rule.
Try these variations to lock in the pattern.
i % 2j % 2 on each rowmax_n and use range(..., -2)n.print(j, end="") stays on the line; print() advances — mix them carefully.max_n > 0 for interactive programs; max_n = 1 should print a single 1.Quick Takeaway: outer loop steps by 2 for odd widths, inner loop prints 1..i, then break the line.
| Program | Time | Extra space |
|---|---|---|
| Nested loops (Examples 1–2) | O(max²) | O(1) |
| Step by 1 (Example 3) | O(max²) | O(1) |
The odd-length descending number triangle is a compact lesson in loop steps: range(..., -2) skips even widths while the inner loop always prints 1..i. Master the odd-only version, then compare with range(..., -1) for a full descending triangle.
Practice the three examples above, then continue to Program 15 for the alternating binary triangle.
Use range(max_n, 0, -2) for odd-only rows and for j in range(1, i + 1): for ascending digits — validate max_n when reading input.
-2 skips even widths before codingprint(j, end="") for digits and print() after each rowmax_n ≥ 1 for interactive programsint(input()) in try/except ValueError before using max_nprint() inside the inner digit looprange(..., -1) when you meant odd-only rowsmax_n = 1 edge casePrint the pattern the beginner-friendly way.
Only odd row widths
DefinitionSteps by 2 downward
CodeAlways prints 1..i
CodeEnds each row
I/OO(n²) time
AnalysisOnly odd-length rows print. The outer loop uses range(..., -2) (7, 5, 3, 1) and the inner loop prints 1..i — still O(n²) total digit prints for maximum width n.
Move on to the alternating binary number triangle in the Python number-pattern series.
12 people found this page helpful