Acwing典中典系列
普通数字三角形
正方形数三dp 摘花生
正方形数三dp 最低通行费
多路径数三dp 方格取数
多路径数三dp 传纸条
记忆化搜索dp 滑雪
LeetCode
64. 最小路径和
思路:
正常的三角形思路,但是我们能如何优化呢?
class Solution {public int minPathSum(int[][] grid) {//数字三角形int m = grid.length, n = grid[0].length;int[][] f = new int[m + 1][n + 1];f[0][1] = 0; f[1][0] = 0;for (int i = 1; i <= m; i ++){if (i > 1)f[i][0] = Integer.MAX_VALUE;for (int j = 1; j <= n; j++){if (j > 1)f[0][j] = Integer.MAX_VALUE;f[i][j] = Math.min(f[i - 1][j], f[i][j - 1]) + grid[i - 1][j - 1];}}return f[m][n];}}
典中典120. 三角形最小路径和
思路1
经典的数字三角形问题,时间复杂度o(n^2), 空间复杂度o(n^2)
class Solution {public int minimumTotal(List<List<Integer>> triangle) {int m = triangle.size(), n = triangle.get(m - 1).size();int[][] f= new int [m + 1][n + 1];for (int i = 0; i <= m; i ++){for (int j = 0; j <= n; j ++)f[i][j] = Integer.MAX_VALUE;}f[0][0] = 0;for (int i = 1; i <= m; i ++)for(int j = 1; j <= i; j ++){int w = triangle.get(i - 1).get(j - 1);f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + w;}int res = Integer.MAX_VALUE;for (int i = 1; i <= n; i ++)res = Math.min(res, f[m][i]);return res;}}
思路2 优化空间复杂度到o(1)
class Solution {public int minimumTotal(List<List<Integer>> triangle) {int m = triangle.size(), n = triangle.get(m - 1).size();for (int i = m - 2; i >= 0; i--){for (int j = i; j >= 0; j--){int tmp = Math.min(triangle.get(i + 1).get(j), triangle.get(i + 1).get(j + 1)) + triangle.get(i).get(j);triangle.get(i).set(j, tmp);}}return triangle.get(0).get(0);}}
329. 矩阵中的最长递增路径 记忆化搜索
思路:
和滑雪一模一样,记忆化搜索dp
class Solution {int[] dx = new int[]{0, -1, 0, 1};int[] dy = new int[]{-1, 0, 1, 0};int[][] f;int m, n;public int longestIncreasingPath(int[][] matrix) {//记忆化搜索dp, 由于f[i,j] 依赖于f[i , j + 1],需要先搜索把f[i, j + 1]计算出来m = matrix.length; n = matrix[0].length;f = new int[m][n];for (int i = 0; i < m; i ++)Arrays.fill(f[i], -1);int res = Integer.MIN_VALUE;for (int i = 0; i < m; i ++){for (int j = 0; j < n; j ++){res = Math.max(res, dp(i, j, matrix));}}return res;}public int dp(int x, int y, int[][] matrix){if (f[x][y] != -1) return f[x][y];f[x][y] = 1;for (int i = 0; i < 4; i ++){int nx = dx[i] + x, ny = dy[i] + y;if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;if (matrix[nx][ny] > matrix[x][y])f[x][y] = Math.max(f[x][y], dp(nx, ny, matrix) + 1);}return f[x][y];}}
576. 出界的路径数 记忆化搜索
思路
记忆化搜索,但是超时了
76 / 94 个通过测试用例 超出时间限制
class Solution {int n, m;int limit;boolean[][][] f;int mod =(int)(1e9) + 7;int[] dx = new int[]{0, -1, 0, 1}, dy = new int[]{-1, 0, 1, 0};public int findPaths(int m, int n, int N, int i, int j) {//类似于记忆化搜索?//f[i][j] 表示ij起点 移出边界的最大数量 =一步移除边界+ 周围点最大数量f = new boolean[m][n][N];limit = N; this.n = n; this.m = m;return dp(i, j, 1);}public int dp(int x, int y, int step){int count = 0;if (step > limit) return count;f[x][y][step - 1] = true;for (int i = 0; i < 4; i ++){int nx = x + dx[i]; int ny = y + dy[i];if (nx < 0 || nx >= m || ny < 0 || ny >= n) {count++;continue;}if (f[nx][ny][step - 1] == true)continue;count = (count + dp(nx, ny, step + 1)) % mod;}// System.out.println(x + " " + y + " " + "count :" + count + " " + "step :" + step);return count;}}
倒序dp 174. 地下城游戏
由于这道题中的骑士向后走要依赖于后面一个关卡的消耗的血量。
因此实际上dp[i][j]:只能定义为从 (i,j)出发,到达终点需要的最小血量。
这就要求了,必须从右下向左上dp。
转移方程-dungeon%5Bi%5D%5Bj%5D%2C%201)#card=math&code=f%5Bi%5D%5Bj%5D%20%3D%20max%28min%28f%5Bi%2B1%5D%5Bj%5D%2C%20f%5Bi%5D%5Bj%2B1%5D%29-dungeon%5Bi%5D%5Bj%5D%2C%201%29)(每一关骑士的血量必须>=1)
f[m][n] = 1
class Solution {
public int calculateMinimumHP(int[][] d) {
int m = d.length;
if (m == 0) return 1;
int n = d[0].length;
int[][] f = new int[m+1][n+1];
for (int i = 0; i <= n; i ++)
f[m][i] =Integer.MAX_VALUE;
for (int i = 0; i <= m; i ++)
f[i][n] = Integer.MAX_VALUE;
f[m][n - 1] = 1; f[m - 1][n] = 1;
for (int i = m - 1; i >= 0; i --){
for (int j = n - 1; j >= 0; j--){
f[i][j] = Math.max(Math.min(f[i][j + 1], f[i + 1][j]) - d[i][j], 1);
//System.out.println(i + " " + j + " " + f[i][j]);
}
}
return f[0][0];
}
}
