Topics › Basics › Learn Basic Recursion
Print N to 1 using Recursion
Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given a positive integer N. Print the numbers N, N - 1, ..., 2, 1 in decreasing order without using a loop; recursion is the only form of repetition allowed.
The task is the mirror image of printing 1 to N. It is worth doing separately because it shows that the direction of the output is controlled by two independent choices: which value the first call starts at, and whether the work happens before or after the recursive call. Change either choice and the output flips.
Constraints: 1 ≤ N ≤ 10^4. We treat N ≤ 0 as “print nothing” so the base case gets exercised.
The methods below collect the numbers into a List<Integer> so that the tests can assert on them; replacing out.add(x) with System.out.println(x) gives the printing version.
Example 1
N = 5
output = 5 4 3 2 1 // count down from N to 1
Example 2
N = 1
output = 1 // smallest valid input, one number
Example 3
N = 0
output = (nothing) // no number lies between N and 1
Approach 1: The loop, as a reference
Intuition. A countdown loop starts the counter at N, emits it, and decrements until it drops below 1. Writing this down first tells us precisely what each recursive version has to reproduce.
Algorithm.
- Create an empty list.
- For
ifromNdown to1, appendi. - Return the list.
static List<Integer> iterative(int n) {
List<Integer> out = new ArrayList<>();
for (int i = n; i >= 1; i--) out.add(i);
return out;
}
Complexity. Time O(n), one append per number. Space O(1) beyond the output list.
Approach 2: Parameterised recursion, work first then recurse
Intuition. Turn the loop counter into a parameter. The first call receives i = N; it emits i and then delegates i - 1 to the next call. The loop’s exit condition i < 1 becomes the base case. Because the value is emitted before the recursive call, the output is produced on the way down the call chain, and since we start at N and shrink, the numbers appear in decreasing order.
Compare this with the forward version of printing 1 to N: there the parameter starts at 1 and grows. Same shape, different start and step.
Algorithm.
- Start with
forward(n, out). - In
forward(i, out): ifi < 1, return (base case). - Otherwise append
i, then callforward(i - 1, out).
static List<Integer> recursiveForward(int n) {
List<Integer> out = new ArrayList<>();
forward(n, out);
return out;
}
private static void forward(int i, List<Integer> out) {
if (i < 1) return; // base case: we have gone below 1
out.add(i); // do the work ...
forward(i - 1, out); // ... then recurse towards the base case
}
Complexity. Time O(n): n + 1 calls of constant work each. Space O(n) for the call stack, because all frames are alive when the base case is reached.
Approach 3: Backtracking, recurse first then work
Intuition. Now suppose we are only allowed to count up in the parameter (start at 1, pass i + 1), but still want the output to come out decreasing. The trick is to move the work to after the recursive call. The call for i first lets the recursion handle i + 1 .. N, and only then appends i. The deepest call (i = N) finishes first and appends N; as the stack unwinds, N - 1, N - 2, …, 1 follow. The output is produced on the way up.
This is the backtracking shape: the recursion dives to the end and the useful work happens while returning. It is exactly the opposite pairing from the forward approach, which is why both versions produce the same descending output.
Algorithm.
- Start with
backtrack(1, n, out). - In
backtrack(i, n, out): ifi > n, return (base case). - Otherwise call
backtrack(i + 1, n, out)first, then appendi.
static List<Integer> recursiveBacktrack(int n) {
List<Integer> out = new ArrayList<>();
backtrack(1, n, out);
return out;
}
private static void backtrack(int i, int n, List<Integer> out) {
if (i > n) return; // base case
backtrack(i + 1, n, out); // recurse first ...
out.add(i); // ... print on the way back, so n comes out first
}
Dry run on N = 3:
| call | work before recursing | recursive call | work after it returns |
|---|---|---|---|
backtrack(1) |
none | backtrack(2) |
append 1 |
backtrack(2) |
none | backtrack(3) |
append 2 |
backtrack(3) |
none | backtrack(4) |
append 3 |
backtrack(4) |
i > n, return |
The frames return in the order backtrack(3), backtrack(2), backtrack(1), so the appends happen as 3, 2, 1.
Complexity. Time O(n): n + 1 calls. Space O(n) for the call stack.
The two-by-two picture
Putting this problem next to printing 1 to N gives a small table worth memorising:
| parameter moves | work before the call | work after the call |
|---|---|---|
upward (1 → N) |
prints 1 .. N |
prints N .. 1 |
downward (N → 1) |
prints N .. 1 |
prints 1 .. N |
“Work after the call” reverses the order in which the parameter visits the values. That single fact is behind reversing a linked list recursively, printing a path from a tree root after the recursion reaches a leaf, and many other patterns.
Edge cases and pitfalls
N = 0or negative. Approach 2 starts ati = N; sinceN < 1holds, the base case fires on the very first call and nothing is printed. Approach 3 starts ati = 1; since1 > Nholds, it also returns immediately. Both produce an empty list.- Off-by-one in the base case.
if (i < 1)versusif (i <= 1): the second drops the number1.if (i > n)versusif (i >= n): the second dropsN. Test withN = 1, where both mistakes show up as an empty output. - Base case before work. If the append came before the base-case check in Approach 2, the call
forward(0)would append0. Always check the stopping condition first. - Stack depth.
Nnested frames are needed. The default JVM stack handles theN = 2000used in the tests with plenty of room, butNin the millions needs the loop. - Mutable list parameter. Passing the list down and mutating it is fine because each call appends exactly once. Do not store it in a
staticfield that persists across invocations.
Related problems
- Print 1 to N using Recursion is the same exercise with the output reversed; read both to see the two-by-two table in action.
- Print name N times using recursion and Understand recursion by print something N times are the simplest recursion drills, where only the count changes.
- Sum of First N Numbers turns the countdown into an accumulation.
- Factorial of a given number is the multiplicative version of the same countdown.
- Reverse an array shows parameterised recursion with two indices moving towards each other.