Welcome to Subscribe On Youtube

Formatted question description: https://leetcode.ca/all/576.html

576. Out of Boundary Paths (Medium)

There is an m by n grid with a ball. Given the start coordinate (i,j) of the ball, you can move the ball to adjacent cell or cross the grid boundary in four directions (up, down, left, right). However, you can at most move N times. Find out the number of paths to move the ball out of grid boundary. The answer may be very large, return it after mod 109 + 7.

 

Example 1:

Input: m = 2, n = 2, N = 2, i = 0, j = 0
Output: 6
Explanation:

Example 2:

Input: m = 1, n = 3, N = 3, i = 0, j = 1
Output: 12
Explanation:

 

Note:

  1. Once you move the ball out of boundary, you cannot move it back.
  2. The length and height of the grid is in range [1,50].
  3. N is in range [0,50].

Related Topics: Dynamic Programming, Depth-first Search

Similar Questions:

Solution 1. DP Top-down

// OJ: https://leetcode.com/problems/out-of-boundary-paths/
// Time: O(mnN)
// Space: O(mnN)
typedef long long LL;
class Solution {
    const int dirs[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
    const int mod = 1e9 + 7;
    inline int hash(int x, int y, int n) { return 10000 * x + 100 * y + n; }
    unordered_map<int, int> dp;
    int dfs(int m, int n, int N, int i, int j) {
        if (i < 0 || i >= m || j < 0 || j >= n) return 1;
        if (!N) return 0;
        int key = hash(i, j, N);
        if (dp.count(key)) return dp[key];
        LL cnt = 0;
        for (auto &dir : dirs) cnt = (cnt + dfs(m, n, N - 1, i + dir[0], j + dir[1])) % mod;
        return dp[key] = cnt;
    }
public:
    int findPaths(int m, int n, int N, int i, int j) {
        return dfs(m, n, N, i, j);
    }
};

Solution 2. DP Bottom-up

Let dp[i][j][k] be the number of ways to go out of boundary from point (i, j) using exactly k steps.

dp[i][j][1] is the number of edges the point (i, j) touches.

dp[i][j][k] = Sum( dp[a][b][k - 1] | (a, b) is neighbor of (i, j) )

The answer is Sum( dp[x][y][k] | k = 1, 2, ..., N ).

Follow-up: Why not define dp[i][j][k] as the number of ways to go out of boundary from point (i, j) in k steps?

Because when computing dp[i][j][k], assume we know dp[i][j][k - 1], then we need to compute the ways to go out of boundary with exact k steps.

So we need the number of ways with exact k steps any way.

// OJ: https://leetcode.com/problems/out-of-boundary-paths/
// Time: O(mnN)
// Space: O(mn)
class Solution {
public:
    const int dirs[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
    const int mod = 1e9 + 7;
    int findPaths(int m, int n, int N, int x, int y) {
        if (!N) return 0;
        vector<vector<vector<int>>> dp(m, vector<vector<int>>(n, vector<int>(2)));
        for (int i = 0; i < m; ++i) dp[i][0][1]++, dp[i][n - 1][1]++;
        for (int i = 0; i < n; ++i) dp[0][i][1]++, dp[m - 1][i][1]++;
        int ans = dp[x][y][1];
        for (int k = 2; k <= N; ++k) {
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    int val = 0;
                    for (auto &dir : dirs) {
                        int a = i + dir[0], b = j + dir[1];
                        if (a < 0 || a >= m || b < 0 || b >= n) continue;
                        val = (val + dp[a][b][(k - 1) % 2]) % mod;
                    }
                    dp[i][j][k % 2] = val;
                    if (x == i && y == j) ans = (ans + val) % mod;
                }
            }
        }
        return ans;
    }
};

Solution 3. DP Bottom-up

Let dp[i][j][k] be the number of ways to reach point (i, j) from starting point (x, y) with exactly k - 1 steps.

So dp[x][y][1] = 1.

dp[i][j][k] = Sum( dp[a][b][k - 1] | (a, b) is neighbor of (i, j))

dp[i][j][k] should be count into answer if point (i, j) is at the boundary.

// OJ: https://leetcode.com/problems/out-of-boundary-paths/
// Time: O(mnN)
// Space: O(mn)
// Ref: https://leetcode.com/problems/out-of-boundary-paths/solution/
class Solution {
    const int dirs[4][2] = { {0, 1}, {0, -1}, {-1, 0}, {1, 0} };
    const int mod = 1e9 + 7;
public:
    int findPaths(int m, int n, int N, int x, int y) {
        if (!N) return 0;
        vector<vector<vector<int>>> dp(m, vector<vector<int>>(n, vector<int>(2)));
        dp[x][y][1] = 1;
        int ans = 0;
        for (int k = 1; k <= N; ++k) {
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    int val = dp[i][j][k % 2];
                    if (!i) ans = (ans + val) % mod;
                    if (i == m - 1) ans = (ans + val) % mod;
                    if (!j) ans = (ans + val) % mod;
                    if (j == n - 1) ans = (ans + val) % mod;
                    val = 0;
                    for (auto &dir : dirs) {
                        int a = i + dir[0], b = j + dir[1];
                        if (a < 0 || a >= m || b < 0 || b >= n) continue;
                        val = (val + dp[a][b][k % 2]) % mod;
                    }
                    dp[i][j][(k + 1) % 2] = val;
                }
            }
        }
        return ans;
    }
};
  • class Solution {
        public int findPaths(int m, int n, int N, int i, int j) {
            final int MODULO = 1000000007;
            int outCounts = 0;
            int[][] counts = new int[m][n];
            counts[i][j] = 1;
            int[][] directions = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
            for (int move = 0; move < N; move++) {
                int[][] curCounts = new int[m][n];
                for (int row = 0; row < m; row++) {
                    for (int column = 0; column < n; column++) {
                        int count = counts[row][column];
                        if (count > 0) {
                            for (int[] direction : directions) {
                                int newRow = row + direction[0], newColumn = column + direction[1];
                                if (newRow >= 0 && newRow < m && newColumn >= 0 && newColumn < n)
                                    curCounts[newRow][newColumn] = (curCounts[newRow][newColumn] + count) % MODULO;
                                else
                                    outCounts = (outCounts + count) % MODULO;
                            }
                        }
                    }
                }
                for (int row = 0; row < m; row++) {
                    for (int column = 0; column < n; column++)
                        counts[row][column] = curCounts[row][column];
                }
            }
            return outCounts;
        }
    }
    
    ############
    
    class Solution {
        private int m;
        private int n;
        private int[][][] f;
        private static final int[] DIRS = {-1, 0, 1, 0, -1};
        private static final int MOD = (int) 1e9 + 7;
    
        public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
            this.m = m;
            this.n = n;
            f = new int[m + 1][n + 1][maxMove + 1];
            for (var a : f) {
                for (var b : a) {
                    Arrays.fill(b, -1);
                }
            }
            return dfs(startRow, startColumn, maxMove);
        }
    
        private int dfs(int i, int j, int k) {
            if (i < 0 || i >= m || j < 0 || j >= n) {
                return 1;
            }
            if (f[i][j][k] != -1) {
                return f[i][j][k];
            }
            if (k == 0) {
                return 0;
            }
            int res = 0;
            for (int t = 0; t < 4; ++t) {
                int x = i + DIRS[t];
                int y = j + DIRS[t + 1];
                res += dfs(x, y, k - 1);
                res %= MOD;
            }
            f[i][j][k] = res;
            return res;
        }
    }
    
  • // OJ: https://leetcode.com/problems/out-of-boundary-paths/
    // Time: O(MNK)
    // Space: O(MNK)
    class Solution {
        long m, n, dp[50][50][51] = {}, dirs[4][2] = { {0,1},{0,-1},{-1,0},{1,0} }, mod = 1e9 + 7;
        int dfs(int x, int y, int k) {
            if (x < 0 || x >= m || y < 0 || y >= n) return 1;
            if (k == 0) return 0;
            if (dp[x][y][k] != -1) return dp[x][y][k];
            long cnt = 0;
            for (auto &[dx, dy] : dirs) {
                int a = x + dx, b = y + dy;
                cnt = (dfs(a, b, k - 1) + cnt) % mod;
            }
            return dp[x][y][k] = cnt;
        }
    public:
        int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
            this->m = m;
            this->n = n;
            memset(dp, -1, sizeof(dp));
            return dfs(startRow, startColumn, maxMove);
        }
    };
    
  • class Solution:
        def findPaths(
            self, m: int, n: int, maxMove: int, startRow: int, startColumn: int
        ) -> int:
            @cache
            def dfs(i, j, k):
                if i < 0 or j < 0 or i >= m or j >= n:
                    return 1
                if k <= 0:
                    return 0
                res = 0
                for a, b in [[-1, 0], [1, 0], [0, 1], [0, -1]]:
                    x, y = i + a, j + b
                    res += dfs(x, y, k - 1)
                    res %= mod
                return res
    
            mod = 10**9 + 7
            return dfs(startRow, startColumn, maxMove)
    
    ############
    
    class Solution(object):
      def findPaths(self, m, n, N, x, y):
        dp = [[[0] * n for _ in range(m)] for _ in range(N + 1)]
        dp[0][x][y] = 1
        ans = 0
        mod = 10 ** 9 + 7
        for k in range(1, N + 1):
          for i in range(m):
            for j in range(n):
              if i == 0:
                ans += dp[k - 1][i][j] % mod
              if i == m - 1:
                ans += dp[k - 1][i][j] % mod
              if j == 0:
                ans += dp[k - 1][i][j] % mod
              if j == n - 1:
                ans += dp[k - 1][i][j] % mod
              if i > 0:
                dp[k][i][j] += dp[k - 1][i - 1][j]
              if i < m - 1:
                dp[k][i][j] += dp[k - 1][i + 1][j]
              if j > 0:
                dp[k][i][j] += dp[k - 1][i][j - 1]
              if j < n - 1:
                dp[k][i][j] += dp[k - 1][i][j + 1]
        return ans % mod
    
    
  • func findPaths(m int, n int, maxMove int, startRow int, startColumn int) int {
    	f := make([][][]int, m+1)
    	for i := range f {
    		f[i] = make([][]int, n+1)
    		for j := range f[i] {
    			f[i][j] = make([]int, maxMove+1)
    			for k := range f[i][j] {
    				f[i][j][k] = -1
    			}
    		}
    	}
    	var mod int = 1e9 + 7
    	dirs := []int{-1, 0, 1, 0, -1}
    	var dfs func(i, j, k int) int
    	dfs = func(i, j, k int) int {
    		if i < 0 || i >= m || j < 0 || j >= n {
    			return 1
    		}
    		if f[i][j][k] != -1 {
    			return f[i][j][k]
    		}
    		if k == 0 {
    			return 0
    		}
    		res := 0
    		for t := 0; t < 4; t++ {
    			x, y := i+dirs[t], j+dirs[t+1]
    			res += dfs(x, y, k-1)
    			res %= mod
    		}
    		f[i][j][k] = res
    		return res
    	}
    	return dfs(startRow, startColumn, maxMove)
    }
    

All Problems

All Solutions