A left-shifted descending triangle prints digits i..rows on each row — so the starting digit climbs and the row shrinks from the left.
Remember
Rule: for i = 1..rows
print i..rows
12345
2345
345
45
5 ← rows = 5
Unlike Program 1’s 1..i with a descending outer loop, this one counts up and starts each row at i.
Approach
How to Solve It
Walk i from 1 to rows; print digits from i through rows.
Method
Idea
Best for
Nested loops
Outer = start i; inner prints i..rows
Learning, interviews
input() rows
Same loops; read rows at runtime
Interactive practice
"".join
Build the row string, then print once
Compact style
Pseudocode
Pseudocode
for i from 1 to rows:
for j from i to rows:
print j (no newline)
print newline
Cheat sheet
Goal
Pattern
Set rows
rows = 5
Outer loop
for i in range(1, rows + 1):
Inner loop
for j in range(i, rows + 1): print(j, end="")
End row
print()
Digits per row
rows - i + 1
Join shortcut
print("".join(str(j) for j in range(i, rows + 1)))
vs Program 1
Print i..rows vs 1..i with descending outer
Printing Numbers vs Starting a New Line
API
Effect
Use for
print(j, end="")
Stays on the same line
Each digit
print()
Ends the current line
After the inner loop
Print digits with end="", then break once with print(). Putting print() inside the inner loop prints one digit per line.
Try it
Live Preview
Change the row count and the left-shifted triangle updates instantly.
Whole numbers from 1 to 9. Tap a chip or type a value — the preview redraws as you go.
Live result5 rows · 15 digits
12345
2345
345
45
5
Trace
Worked Walkthrough — rows = 3
Trace each outer i, the inner j range, and the printed row.
i
Inner j
Printed row
1
1..3
123
2
2..3
23
3
3..3
3
Digits per row = rows - i + 1. Total = 6 = 3×4/2.
Code
Python Programs
Three complete programs: fixed rows = 5, input() rows, and a "".join shortcut. Use View Output for sample results.
Example 1 — Fixed rows = 5
Hard-coded height — inner loop starts at i and runs through rows.
Python
rows = 5
for i in range(1, rows + 1):
for j in range(i, rows + 1):
print(j, end="")
print()
Output
12345
2345
345
45
5
How It Works
1. Outer loop.i is the starting digit of that row (1, then 2, then 3…).
2. Inner loop. Print j from i to rows with end="".
3. Newline.print() after the inner loop starts the next shorter row.
Example 2 — input() Rows
Read rows at runtime with input() and int().
Python
rows = int(input("Enter the number of rows: "))
for i in range(1, rows + 1):
for j in range(i, rows + 1):
print(j, end="")
print()
Output (when user enters 4)
Enter the number of rows: 4
1234
234
34
4
How It Works
1. Read rows. Convert the prompt answer with int().
2. Same shape. Inner start is still i — only the height changes.
3. Safer input tip. Bare int(input()) raises ValueError on letters. Prefer:
Safer input
raw = input("Enter the number of rows: ").strip()
try:
rows = int(raw)
except ValueError:
print("Enter a positive whole number.")
raise SystemExit(1)
if rows < 1:
print("Enter a positive whole number.")
raise SystemExit(1)
Example 3 — "".join Shortcut
Build each row as one string, then print once — same shape, fewer print calls.
Python
rows = 5
for i in range(1, rows + 1):
print("".join(str(j) for j in range(i, rows + 1)))
Output
12345
2345
345
45
5
How It Works
1. Same range.range(i, rows + 1) still produces digits i..rows.
2. Join once. Convert each digit to a string, join them, then print the whole row.
3. When to use it. Prefer nested print(j, end="") while learning; use join when you want a shorter style.
Edge Cases & Pitfalls
Check these before calling the solution done.
start at 1
Wrong shape
If the inner loop starts at 1, every row prints 1..rows — a rectangle, not this shift.
print() inside
Vertical digits
If print() is inside the inner loop, each digit lands on its own line.
descending outer
Program 1 mix-up
range(rows, 0, -1) with 1..i is Program 1. Keep range(1, rows + 1) with i..rows here.
rows = 1
Single digit
Output is just 1 — a good sanity check.
multi-digit
Values above 9
When rows > 9, cells become two characters. Keep demos at rows ≤ 9 or add spaces.
input()
Catch ValueError
Letters crash bare int(input()) — wrap in try/except and require rows >= 1.
Analysis
Time and Space Complexity
Program
Time
Extra space
Examples 1–2
O(n²)
O(1)
Join shortcut (Example 3)
O(n²)
O(n) for the row string
Digits per pattern = n + (n-1) + … + 1 = n(n+1)/2 → O(n²).
Remember
Key Takeaways
Rule: for each i, print digits i..rows.
Start at i: the inner loop must begin at i, not 1.
end= vs print(): digits stay on the line; print() advances after each row.
Complexity: total digits = n(n+1)/2 → O(n²).
One line: raise the start digit each row and print straight through to rows.
Frequently Asked Questions
The inner loop starts at j = i, not j = 1. When i increases (1, 2, 3, …), each row begins at that value and prints until rows.
Because each next row starts at a higher i, numbers below i are not printed anymore — the triangle shifts left visually.
print(j, end="") stays on the same line. print() ends the current line. Digits use end=""; the row break uses print() after the inner loop.
Program 1 counts the outer loop down and prints 1..i. Program 2 counts up and prints i..rows — same total prints, different shape.
Change the rows variable or read it with int(input()) — see Example 2.
Yes. Use "".join(str(j) for j in range(i, rows + 1)) then print the row — see Example 3.
O(n²) for n rows because total prints are n+(n-1)+…+1 = n(n+1)/2.
Use try/except ValueError around int(input()) so bad input does not crash the script.
Only one row prints — a single 1.
🤔
Did you know?
Each row starts at i and prints through rows, so the left edge shifts right each line — still O(n²) total prints for n rows.