1215. Stepping Numbers 🔒
Problem Description
A stepping number is a special type of integer where every pair of adjacent digits differs by exactly 1.
For example:
321
is a stepping number because: 3→2 differs by 1, and 2→1 differs by 1421
is not a stepping number because: 4→2 differs by 2
Given two integers low
and high
, you need to find all stepping numbers within the range [low, high]
(inclusive) and return them as a sorted list.
The solution uses a BFS (Breadth-First Search) approach. It starts by handling the special case where 0
might be in the range (since 0 is considered a stepping number). Then it initializes a queue with single-digit numbers 1
through 9
(all single-digit numbers are stepping numbers).
The algorithm works by:
- Taking a number
v
from the queue - If
v
exceedshigh
, stop the search - If
v
is within[low, high]
, add it to the answer - Generate new stepping numbers by appending valid digits to
v
:- Get the last digit
x
ofv
- If
x > 0
, appendx-1
to createv * 10 + (x-1)
- If
x < 9
, appendx+1
to createv * 10 + (x+1)
- Get the last digit
- Add these new numbers to the queue for further processing
This approach ensures all stepping numbers are generated in increasing order, automatically providing a sorted result.
Flowchart Walkthrough
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph?
- No: While we can think of stepping numbers as forming a tree-like structure where each number can generate new numbers, the problem itself isn't explicitly about graph nodes and edges.
Need to solve for kth smallest/largest?
- No: We need to find all stepping numbers in a range, not the kth smallest/largest.
Involves Linked Lists?
- No: The problem doesn't involve linked list data structures.
Does the problem have small constraints?
- No: The constraints can be quite large (up to
10^9
typically), and we need an efficient approach rather than pure brute force. However, the branching factor is limited - each digit can only generate at most 2 new digits (±1).
BFS?
- Yes: BFS is the appropriate choice here because:
- We're generating numbers level by level (1-digit, then 2-digit, then 3-digit, etc.)
- We want to explore all possibilities at each "depth" before moving deeper
- The queue-based approach naturally generates numbers in ascending order
- We can stop early when we exceed the
high
boundary
Conclusion: The flowchart suggests using BFS (Breadth-First Search) for systematically generating stepping numbers. Starting from single digits (1-9), we expand each number by appending valid adjacent digits (last digit ±1), exploring all numbers of the same length before moving to longer numbers. This ensures we find all stepping numbers in the given range efficiently.
Intuition
Think about how stepping numbers are constructed - each digit must differ from its neighbor by exactly 1. This means if we have a stepping number, we can generate new stepping numbers by appending valid digits to it.
Starting with a stepping number like 12
, we can only append 1
or 3
to maintain the stepping property (since the last digit is 2
, the next digit must be 2±1
). This gives us 121
and 123
.
This generation process naturally forms a tree structure:
- Root: single digits
1-9
(all are stepping numbers) - Children: generated by appending valid digits
The key insight is that we want to explore this tree level by level (BFS) rather than depth-first because:
- Natural ordering: BFS explores all n-digit numbers before moving to (n+1)-digit numbers, which means we generate numbers in ascending order
- Early termination: Once we generate a number larger than
high
, we know all subsequent numbers at that level and deeper will also exceedhigh
- Systematic generation: Using a queue ensures we don't miss any stepping numbers and don't generate duplicates
The algorithm mimics building numbers digit by digit. For each stepping number in our queue:
- Extract its last digit
x
- If
x > 0
, we can appendx-1
(multiply by 10 and addx-1
) - If
x < 9
, we can appendx+1
(multiply by 10 and addx+1
)
This way, every stepping number acts as a "seed" to generate longer stepping numbers, and the BFS approach ensures we find them all in the desired range efficiently.
Learn more about Breadth-First Search, Math and Backtracking patterns.
Solution Approach
The implementation uses BFS with a queue to systematically generate all stepping numbers in the range [low, high]
.
Initial Setup:
- Create an empty list
ans
to store results - Handle the special case: if
low == 0
, add0
to the answer (since 0 is considered a stepping number) - Initialize a queue with all single-digit numbers
1
through9
usingdeque(range(1, 10))
BFS Process: The main loop continues while the queue is not empty:
-
Extract and Check: Pop the leftmost element
v
from the queue- If
v > high
, break immediately (all subsequent numbers will be larger) - If
v >= low
, add it to the answer list
- If
-
Generate New Numbers: Based on the last digit
x
of current numberv
:- Extract last digit:
x = v % 10
- If
x > 0
: Create new number by appendingx-1
:v * 10 + x - 1
- If
x < 9
: Create new number by appendingx+1
:v * 10 + x + 1
- Add these new numbers to the queue for future processing
- Extract last digit:
Why This Works:
- The queue processes numbers in increasing order (all n-digit numbers before (n+1)-digit numbers)
- Each number generates at most 2 new stepping numbers
- The condition
v > high
ensures we stop as soon as we exceed the range - The condition
x > 0
andx < 9
prevents invalid digits (no negative digits or digits > 9)
Example Trace:
For range [10, 20]
:
- Queue starts with:
[1, 2, 3, ..., 9]
- Process
1
: generates10
and12
→ add both to queue - Process
2
: generates21
and23
→ add to queue (but21
> 20, so we'd stop) 10
and12
are within range, so they're added to answer
The algorithm naturally produces a sorted result since BFS explores numbers level by level in ascending order.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's trace through finding all stepping numbers in the range [10, 25]
.
Initial Setup:
ans = []
(empty result list)- Since
low = 10 ≠ 0
, we don't add 0 - Queue initialized with:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
BFS Processing:
Round 1: Process v = 1
v = 1 < low
, so don't add to answer- Last digit
x = 1
- Since
x > 0
: generate1 * 10 + (1-1) = 10
→ add to queue - Since
x < 9
: generate1 * 10 + (1+1) = 12
→ add to queue - Queue now:
[2, 3, 4, 5, 6, 7, 8, 9, 10, 12]
Round 2: Process v = 2
v = 2 < low
, so don't add to answer- Last digit
x = 2
- Since
x > 0
: generate2 * 10 + (2-1) = 21
→ add to queue - Since
x < 9
: generate2 * 10 + (2+1) = 23
→ add to queue - Queue now:
[3, 4, 5, 6, 7, 8, 9, 10, 12, 21, 23]
Rounds 3-9: Process v = 3
through v = 9
- All are
< low
, so none added to answer - Each generates two new numbers added to queue
Round 10: Process v = 10
v = 10 >= low
, so add 10 to answer:ans = [10]
- Last digit
x = 0
- Since
x = 0
(not > 0): can't generate withx-1
- Since
x < 9
: generate10 * 10 + (0+1) = 101
→ add to queue
Round 11: Process v = 12
v = 12 >= low
, so add 12 to answer:ans = [10, 12]
- Last digit
x = 2
- Since
x > 0
: generate12 * 10 + (2-1) = 121
→ add to queue - Since
x < 9
: generate12 * 10 + (2+1) = 123
→ add to queue
Round 12: Process v = 21
v = 21 >= low
, so add 21 to answer:ans = [10, 12, 21]
- Last digit
x = 1
- Since
x > 0
: generate21 * 10 + (1-1) = 210
→ add to queue - Since
x < 9
: generate21 * 10 + (1+1) = 212
→ add to queue
Round 13: Process v = 23
v = 23 >= low
, so add 23 to answer:ans = [10, 12, 21, 23]
- Last digit
x = 3
- Since
x > 0
: generate23 * 10 + (3-1) = 232
→ add to queue - Since
x < 9
: generate23 * 10 + (3+1) = 234
→ add to queue
Round 14: Process v = 32
v = 32 > high = 25
, so break the loop
Final Result: [10, 12, 21, 23]
All numbers in our answer are stepping numbers:
10
: 1→0 differs by 1 ✓12
: 1→2 differs by 1 ✓21
: 2→1 differs by 1 ✓23
: 2→3 differs by 1 ✓
Solution Implementation
1from collections import deque
2from typing import List
3
4class Solution:
5 def countSteppingNumbers(self, low: int, high: int) -> List[int]:
6 """
7 Find all stepping numbers in the range [low, high].
8 A stepping number is a number where each adjacent digit differs by exactly 1.
9
10 Args:
11 low: Lower bound of the range (inclusive)
12 high: Upper bound of the range (inclusive)
13
14 Returns:
15 List of all stepping numbers in the given range
16 """
17 result = []
18
19 # Special case: 0 is a stepping number if it's in range
20 if low == 0:
21 result.append(0)
22
23 # Initialize queue with single digits 1-9 as starting points
24 queue = deque(range(1, 10))
25
26 # BFS to generate stepping numbers
27 while queue:
28 current_number = queue.popleft()
29
30 # Stop processing if number exceeds upper bound
31 if current_number > high:
32 break
33
34 # Add to result if number is within range
35 if current_number >= low:
36 result.append(current_number)
37
38 # Get the last digit of current number
39 last_digit = current_number % 10
40
41 # Generate next stepping numbers by appending valid digits
42 # Append (last_digit - 1) if it's valid (not negative)
43 if last_digit > 0:
44 next_number = current_number * 10 + last_digit - 1
45 queue.append(next_number)
46
47 # Append (last_digit + 1) if it's valid (not > 9)
48 if last_digit < 9:
49 next_number = current_number * 10 + last_digit + 1
50 queue.append(next_number)
51
52 return result
53
1class Solution {
2 /**
3 * Finds all stepping numbers in the range [low, high].
4 * A stepping number is an integer where each adjacent digit differs by exactly 1.
5 *
6 * @param low The lower bound of the range (inclusive)
7 * @param high The upper bound of the range (inclusive)
8 * @return List of all stepping numbers in the given range
9 */
10 public List<Integer> countSteppingNumbers(int low, int high) {
11 List<Integer> result = new ArrayList<>();
12
13 // Special case: 0 is considered a stepping number if it's in range
14 if (low == 0) {
15 result.add(0);
16 }
17
18 // BFS queue to generate stepping numbers
19 Deque<Long> queue = new ArrayDeque<>();
20
21 // Initialize queue with single-digit numbers (1-9)
22 // These are all valid stepping numbers
23 for (long digit = 1; digit < 10; ++digit) {
24 queue.offer(digit);
25 }
26
27 // BFS to generate stepping numbers
28 while (!queue.isEmpty()) {
29 long currentNumber = queue.pollFirst();
30
31 // If current number exceeds high, stop processing
32 if (currentNumber > high) {
33 break;
34 }
35
36 // If current number is within range, add to result
37 if (currentNumber >= low) {
38 result.add((int) currentNumber);
39 }
40
41 // Get the last digit of current number
42 int lastDigit = (int) (currentNumber % 10);
43
44 // Generate next stepping numbers by appending valid digits
45 // Valid next digit is lastDigit - 1 (if lastDigit > 0)
46 if (lastDigit > 0) {
47 queue.offer(currentNumber * 10 + lastDigit - 1);
48 }
49
50 // Valid next digit is lastDigit + 1 (if lastDigit < 9)
51 if (lastDigit < 9) {
52 queue.offer(currentNumber * 10 + lastDigit + 1);
53 }
54 }
55
56 return result;
57 }
58}
59
1class Solution {
2public:
3 vector<int> countSteppingNumbers(int low, int high) {
4 vector<int> result;
5
6 // Special case: 0 is a stepping number if it's in range
7 if (low == 0) {
8 result.push_back(0);
9 }
10
11 // BFS queue to generate stepping numbers
12 queue<long long> bfsQueue;
13
14 // Initialize queue with single-digit numbers (1-9)
15 // These are all stepping numbers by definition
16 for (int digit = 1; digit <= 9; ++digit) {
17 bfsQueue.push(digit);
18 }
19
20 // BFS to generate all stepping numbers in range
21 while (!bfsQueue.empty()) {
22 long long currentNumber = bfsQueue.front();
23 bfsQueue.pop();
24
25 // If current number exceeds high, stop processing
26 // Since BFS generates numbers in increasing order of digits
27 if (currentNumber > high) {
28 break;
29 }
30
31 // If current number is within range, add to result
32 if (currentNumber >= low) {
33 result.push_back(currentNumber);
34 }
35
36 // Generate next stepping numbers by appending valid digits
37 int lastDigit = currentNumber % 10;
38
39 // Append (lastDigit - 1) if valid
40 if (lastDigit > 0) {
41 bfsQueue.push(currentNumber * 10 + lastDigit - 1);
42 }
43
44 // Append (lastDigit + 1) if valid
45 if (lastDigit < 9) {
46 bfsQueue.push(currentNumber * 10 + lastDigit + 1);
47 }
48 }
49
50 return result;
51 }
52};
53
1/**
2 * Finds all stepping numbers within the given range [low, high].
3 * A stepping number is a number where the absolute difference between
4 * every two consecutive digits is exactly 1.
5 *
6 * @param low - The lower bound of the range (inclusive)
7 * @param high - The upper bound of the range (inclusive)
8 * @returns An array containing all stepping numbers in the range
9 */
10function countSteppingNumbers(low: number, high: number): number[] {
11 const result: number[] = [];
12
13 // Special case: 0 is considered a stepping number if it's in range
14 if (low === 0) {
15 result.push(0);
16 }
17
18 // Initialize queue with single-digit numbers (1-9)
19 // These are all valid stepping numbers
20 const queue: number[] = [];
21 for (let digit = 1; digit < 10; digit++) {
22 queue.push(digit);
23 }
24
25 // BFS approach: generate stepping numbers by extending existing ones
26 while (queue.length > 0) {
27 const currentNumber = queue.shift()!;
28
29 // Stop processing if we've exceeded the upper bound
30 if (currentNumber > high) {
31 break;
32 }
33
34 // Add current number to result if it's within range
35 if (currentNumber >= low) {
36 result.push(currentNumber);
37 }
38
39 // Get the last digit of current number
40 const lastDigit = currentNumber % 10;
41
42 // Generate next stepping numbers by appending digits
43 // that differ by 1 from the last digit
44
45 // If last digit > 0, we can append (lastDigit - 1)
46 if (lastDigit > 0) {
47 const nextNumber = currentNumber * 10 + lastDigit - 1;
48 queue.push(nextNumber);
49 }
50
51 // If last digit < 9, we can append (lastDigit + 1)
52 if (lastDigit < 9) {
53 const nextNumber = currentNumber * 10 + lastDigit + 1;
54 queue.push(nextNumber);
55 }
56 }
57
58 return result;
59}
60
Time and Space Complexity
The time complexity is O(10 × 2^(log M))
, where M
is the value of high
. This can be understood as follows:
- The algorithm uses BFS to generate all stepping numbers starting from single digits 1-9
- Each stepping number can branch into at most 2 new stepping numbers (by appending either
last_digit - 1
orlast_digit + 1
) - The maximum depth of this tree is approximately
log₁₀(high)
(the number of digits inhigh
) - At each level
d
, there can be at most9 × 2^(d-1)
stepping numbers - The total number of stepping numbers processed is bounded by
O(9 × (2^0 + 2^1 + ... + 2^(log M - 1)))
=O(9 × 2^(log M))
≈O(10 × 2^(log M))
The space complexity is O(2^(log M))
, where M
is the value of high
. This is because:
- The queue
q
stores stepping numbers during BFS traversal - In the worst case, the queue can hold up to
O(2^(log M))
stepping numbers at once (when processing numbers with maximum digits) - The answer list
ans
also stores up toO(2^(log M))
stepping numbers in the range[low, high]
- Therefore, the total space complexity is
O(2^(log M))
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Queue Initialization Order
A common mistake is initializing the queue incorrectly or processing numbers in the wrong order, which can lead to unsorted results or missing numbers.
Pitfall Example:
# Wrong: Using a different data structure or wrong initialization queue = [1, 2, 3, 4, 5, 6, 7, 8, 9] # Using list instead of deque # Or initializing with wrong order/values queue = deque([9, 8, 7, 6, 5, 4, 3, 2, 1]) # Reverse order
Solution:
Always use deque(range(1, 10))
to ensure proper BFS traversal. The deque ensures O(1) append and popleft operations, and the correct order ensures numbers are processed in ascending order.
2. Forgetting to Handle Zero as a Special Case
Zero is a valid stepping number but cannot be generated through the BFS process since we start with digits 1-9.
Pitfall Example:
def countSteppingNumbers(self, low: int, high: int) -> List[int]:
result = []
# Missing: if low == 0: result.append(0)
queue = deque(range(1, 10))
# ... rest of code
Solution:
Always check if low == 0
at the beginning and add 0 to the result if true. Alternatively, check if low <= 0 <= high
for a more explicit range check.
3. Breaking Too Early or Too Late
The break condition if current_number > high
must be placed correctly to avoid missing valid numbers or processing unnecessary ones.
Pitfall Example:
while queue: current_number = queue.popleft() if current_number >= low: result.append(current_number) # Wrong: Breaking after adding to result might miss valid numbers if current_number > high: break # Generate next numbers...
Solution: Place the break immediately after popping from queue and before checking if the number should be added to results. This ensures we don't add numbers > high but also don't miss valid numbers in the queue.
4. Generating Invalid Next Numbers
When appending digits, failing to check boundaries can create invalid stepping numbers or cause errors.
Pitfall Example:
last_digit = current_number % 10 # Wrong: Not checking if last_digit - 1 is valid next_number = current_number * 10 + last_digit - 1 queue.append(next_number) # Could append number ending in -1 # Wrong: Not checking if last_digit + 1 is valid next_number = current_number * 10 + last_digit + 1 queue.append(next_number) # Could append number ending in 10
Solution: Always validate:
- Only append
(last_digit - 1)
whenlast_digit > 0
- Only append
(last_digit + 1)
whenlast_digit < 9
5. Overflow for Large Ranges
For very large values of high
, the generated numbers might exceed integer limits or cause memory issues with a huge queue.
Pitfall Example:
# If high is near MAX_INT, multiplication by 10 could overflow next_number = current_number * 10 + last_digit + 1 # No check for potential overflow
Solution: Add a check before appending to queue:
if last_digit < 9: next_number = current_number * 10 + last_digit + 1 if next_number <= high: # Additional safety check queue.append(next_number)
This prevents adding numbers to the queue that would exceed the range, improving both safety and efficiency.
Which of these properties could exist for a graph but not a tree?
Recommended Readings
https assets algo monster cover_photos bfs svg Breadth First Search on Trees Hopefully by this time you've drunk enough DFS Kool Aid to understand its immense power and seen enough visualization to create a call stack in your mind Now let me introduce the companion spell Breadth First Search BFS
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Backtracking Template Prereq DFS with States problems dfs_with_states Combinatorial search problems Combinatorial search problems involve finding groupings and assignments of objects that satisfy certain conditions Finding all permutations combinations subsets and solving Sudoku are classic combinatorial problems The time complexity of combinatorial problems often grows rapidly with the size of
Want a Structured Path to Master System Design Too? Don’t Miss This!