Number of Ways to Stay in the Same Place After Some Steps — Hard Problem & Solution
A pointer sits at index 0 of an array of length arrLen. In one step it may move one left, one right, or stay, never leaving the array.
- Difficulty: Hard
- Topics: Dynamic Programming
- Asked at: Amazon, Google, Microsoft
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
A pointer sits at index 0 of an array of length arrLen. In one step it may move one left, one right, or stay, never leaving the array.
Return the number of step sequences of length exactly steps that leave the pointer back at index 0, modulo 10⁹ + 7.
Example 1
Input: steps = 3, arrLen = 2
Output: 4
Explanation: `stay,stay,stay`; `stay,right,left`; `right,left,stay`; `right,stay,left`.
Example 2
Input: steps = 2, arrLen = 4
Output: 2
Explanation: `stay,stay` and `right,left`.
Example 3
Input: steps = 4, arrLen = 2
Output: 8
Constraints
1 <= steps <= 5001 <= arrLen <= 10^6
How to solve Number of Ways to Stay in the Same Place After Some Steps
Layered DP over the step count. dp[p] counts the sequences that leave the pointer at index p. Each step spreads every position's count to itself and to its two neighbours, staying inside the array.
Approach
- Set the usable width to
min(arrLen, steps + 1)— anything beyond is unreachable. - Start with
dp[0] = 1. - Repeat
stepstimes: buildnextby addingdp[p]intonext[p],next[p-1]andnext[p+1]where those exist, modulo 10⁹ + 7. - Return
dp[0].
Why it works
Capping the width is what makes the problem tractable at arrLen = 10⁶: to return to index 0 in steps moves the pointer can never have gone further than steps / 2, and even the generous bound steps + 1 keeps the table at 501 entries. Without the cap the DP would allocate a million-wide row 500 times over for positions that can never be reached, let alone returned from.
Complexity
- Time —
O(steps · min(arrLen, steps)) - Space —
O(min(arrLen, steps))
Pitfalls
- Allocating
arrLencells is the trap the constraints are built around. - The pointer must not step outside the array, so the edges have fewer options.
- Sequences are counted, not final positions — staying put is a distinct move.
Reference solution
Python
def numWays(steps: int, arrLen: int) -> int:
MOD = 10**9 + 7
width = min(arrLen, steps + 1)
dp = [0] * width
dp[0] = 1
for _ in range(steps):
nxt = [0] * width
for p in range(width):
if dp[p] == 0:
continue
nxt[p] = (nxt[p] + dp[p]) % MOD
if p > 0:
nxt[p - 1] = (nxt[p - 1] + dp[p]) % MOD
if p + 1 < width:
nxt[p + 1] = (nxt[p + 1] + dp[p]) % MOD
dp = nxt
return dp[0]JavaScript
var numWays = function(steps, arrLen) {
var MOD = 1000000007;
var width = Math.min(arrLen, steps + 1), p;
var dp = [];
for (p = 0; p < width; p++) dp.push(0);
dp[0] = 1;
for (var s = 0; s < steps; s++) {
var next = [];
for (p = 0; p < width; p++) next.push(0);
for (p = 0; p < width; p++) {
if (dp[p] === 0) continue;
next[p] = (next[p] + dp[p]) % MOD;
if (p > 0) next[p - 1] = (next[p - 1] + dp[p]) % MOD;
if (p + 1 < width) next[p + 1] = (next[p + 1] + dp[p]) % MOD;
}
dp = next;
}
return dp[0];
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.