576.出界的路径数

88 阅读1分钟

题目:
给你一个大小为 m x n 的网格和一个球。球的起始坐标为 [startRow, startColumn] 。你可以将球移到在四个方向上相邻的单元格内(可以穿过网格边界到达网格之外)。你 最多 可以移动 maxMove 次球。

给你五个整数 mnmaxMovestartRow 以及 startColumn ,找出并返回可以将球移出边界的路径数量。因为答案可能非常大,返回对 109 + 7 取余 后的结果。
算法: 方法一:记忆化搜索+DFS

func findPaths(m int, n int, maxMove int, startRow int, startColumn int) int {
	dp := make([][]int, m)
	for i := range dp {
		dp[i] = make([]int, m)
	}
	modVal :=  1000000000 + 7
	cache := make(map[int]int, 0)
	var dfs func (i, j, k int) int
	// 执行了很多重复的dfs(i,j,k),所以将三个参数i,j,k记忆化
	dfs = func(i, j, k int) int {
		if k < 0 {
			return 0
		}
		key := i * 2500 + j * 50 + k
		if val, ok := cache[key]; ok {
			return val
		} 
		if i < 0 || j < 0 || i == m ||j == n{
			return 1
		}
		cnt := 0
		cnt = (cnt + dfs(i - 1, j, k - 1)) % modVal
		cnt = (cnt + dfs(i + 1, j, k - 1)) % modVal
		cnt = (cnt + dfs(i, j - 1, k - 1)) % modVal 
		cnt = (cnt +  dfs(i, j + 1, k - 1)) % modVal
		cache[key] = cnt % modVal
		return cnt
	}
	
	return dfs(startRow, startColumn, maxMove)
}

方法二:动态规划

func findPaths(m int, n int, maxMove int, startRow int, startColumn int) int {
	// dp[k][i][j] maxMove=k,坐标为(i,j)的路径数量
	// dp[k][i][j] = dp[k - 1][i - 1][j] + dp[k - 1][i + 1][j] 
	// + dp[k - 1][i][j - 1] + dp[k - 1][i][j + 1]  k > 0时 
	dp := make([][][]int, maxMove + 1)
	for k := range dp {
		dp[k] = make([][]int, m)
		for i := range dp[k] {
			dp[k][i] = make([]int, n)
		}
	}
	mod := 1000000007
	ans := 0 
	dicts := [][]int{[]int{-1,0},[]int{1,0},[]int{0,-1},[]int{0,1}}
	dp[0][startRow][startColumn] = 1
	for k := 0; k < maxMove; k ++ {
		for i := 0; i < m; i ++ {
			for j := 0; j < n; j ++ {
				count := dp[k][i][j]
				if count > 0 {
					for _, dict := range dicts {
						i1 := dict[0] + i
						j1 := dict[1] + j
						if 0 <= i1 && i1 < m && 0 <= j1 && j1 < n {
							dp[k + 1][i1][j1] = (dp[k + 1][i1][j1] + count) % mod
						} else {
							ans = (ans + count) % mod
						}
					}				
				}			
			}
		}
	}
	return ans

}