classSolution: defmaxMoves(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) @cache defdfs(i: int, j: int) -> int: if j == n - 1: return0 res = 0 for k in i - 1, i, i + 1: if0 <= k < m and grid[k][j + 1] > grid[i][j]: res = max(res, dfs(k, j + 1) + 1) return res returnmax(dfs(i, 0) for i inrange(m))
funcmaxMoves(grid [][]int) (ans int) { m, n := len(grid), len(grid[0]) memo := make([][]int, m) for i := range memo { memo[i] = make([]int, n) for j := range memo[i] { memo[i][j] = -1// -1 表示没被计算过 } } var dfs func(int, int)int dfs = func(i, j int) (res int) { if j == n-1 { return } p := &memo[i][j] if *p != -1 { return *p } for k := max(i-1, 0); k < min(i+2, m); k++ { if grid[k][j+1] > grid[i][j] { res = max(res, dfs(k, j+1)+1) } } *p = res // 记忆化 return } for i := 0; i < m; i++ { ans = max(ans, dfs(i, 0)) } return }
funcmin(a, b int)int { if b < a { return b }; return a } funcmax(a, b int)int { if b > a { return b }; return a }
复杂度分析
时间复杂度:\mathcal{O}(mn),其中 m 和 n 分别为 grid 的行数和列数。动态规划的时间复杂度 = 状态个数 \times 单个状态的计算时间。本题中状态个数等于 \mathcal{O}(mn),单个状态的计算时间为 \mathcal{O}(1),因此时间复杂度为 \mathcal{O}(mn)。
空间复杂度:\mathcal{O}(mn)。
1:1 翻译成递推
根据视频中讲的,我们可以去掉递归中的「递」,只保留「归」的部分,即自底向上计算。
做法:
dfs 改成 f 数组。
递归改成循环(每个参数都对应一层循环)。由于递归是从左向右移动,所以递推是从右到左移动。
递归边界改成 f 数组的初始值。本题可以直接把 f[i][j] 初始化为 0。
[sol2-Python3]
1 2 3 4 5 6 7 8 9 10
classSolution: defmaxMoves(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) f = [[0] * n for _ inrange(m)] for j inrange(n - 2, -1, -1): for i, row inenumerate(grid): for k in i - 1, i, i + 1: if0 <= k < m and grid[k][j + 1] > row[j]: f[i][j] = max(f[i][j], f[k][j + 1] + 1) returnmax(row[0] for row in f)
[sol2-Java]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution { publicintmaxMoves(int[][] grid) { intm= grid.length, n = grid[0].length; varf=newint[m][n]; for (intj= n - 2; j >= 0; j--) for (inti=0; i < m; i++) for (intk= Math.max(i - 1, 0); k < Math.min(i + 2, m); k++) if (grid[k][j + 1] > grid[i][j]) f[i][j] = Math.max(f[i][j], f[k][j + 1] + 1); intans=0; for (inti=0; i < m; i++) ans = Math.max(ans, f[i][0]); return ans; } }
[sol2-C++]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classSolution { public: intmaxMoves(vector<vector<int>> &grid){ int m = grid.size(), n = grid[0].size(), f[m][n]; memset(f, 0, sizeof(f)); for (int j = n - 2; j >= 0; j--) for (int i = 0; i < m; i++) for (int k = max(i - 1, 0); k < min(i + 2, m); k++) if (grid[k][j + 1] > grid[i][j]) f[i][j] = max(f[i][j], f[k][j + 1] + 1); int ans = 0; for (int i = 0; i < m; i++) ans = max(ans, f[i][0]); return ans; } };
funcmaxMoves(grid [][]int) (ans int) { m, n := len(grid), len(grid[0]) f := make([][]int, m) for i := range f { f[i] = make([]int, n) } for j := n - 2; j >= 0; j-- { for i, row := range grid { for k := max(i-1, 0); k < min(i+2, m); k++ { if grid[k][j+1] > row[j] { f[i][j] = max(f[i][j], f[k][j+1]+1) } } } } for _, r := range f { ans = max(ans, r[0]) } return }
funcmin(a, b int)int { if b < a { return b }; return a } funcmax(a, b int)int { if b > a { return b }; return a }
复杂度分析
时间复杂度:\mathcal{O}(mn),其中 m 和 n 分别为 grid 的行数和列数。动态规划的时间复杂度 = 状态个数 \times 单个状态的计算时间。本题中状态个数等于 \mathcal{O}(mn),单个状态的计算时间为 \mathcal{O}(1),因此时间复杂度为 \mathcal{O}(mn)。
classSolution: defmaxMoves(self, grid: List[List[int]]) -> int: m, n = len(grid), len(grid[0]) q = range(m) vis = [-1] * m for j inrange(n - 1): tmp = q q = [] for i in tmp: for k in i - 1, i, i + 1: if0 <= k < m and vis[k] != j and grid[k][j + 1] > grid[i][j]: vis[k] = j # 时间戳标记,避免重复创建 vis 数组 q.append(k) iflen(q) == 0: return j return n - 1
funcmaxMoves(grid [][]int)int { m, n := len(grid), len(grid[0]) vis := make([]int, m) q := make([]int, m) for i := range q { q[i] = i } for j := 0; j < n-1; j++ { tmp := q q = nil for _, i := range tmp { for k := max(i-1, 0); k < min(i+2, m); k++ { if vis[k] != j+1 && grid[k][j+1] > grid[i][j] { vis[k] = j + 1// 时间戳标记,避免重复创建 vis 数组 q = append(q, k) } } } if q == nil { return j } } return n - 1 }
funcmin(a, b int)int { if b < a { return b }; return a } funcmax(a, b int)int { if b > a { return b }; return a }