LeetCode 64. Minimum Path Sum

mac2024-04-11  41

题目:

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

Example:

Input: [   [1,3,1], [1,5,1], [4,2,1] ] Output: 7 Explanation: Because the path 1→3→1→1→1 minimizes the sum.

亚麻OA基础版。这道题要求从一个二维数组从左上到右下的路径中的最少之和,每次只能往右或者往下走。这道题的做法应该是DP,但我也有考虑过DFS、BFS之类的,不知道是不是想偏了。如果用二维DP做的话非常简单,先把第一行和第一列给定义好,然后剩下的元素就取dp[i][j] = min(dp[i - 1][j], dp[i][j - 1])并加上当前的grid值即可。代码写起来还是非常简单的,时空复杂度都是O(n^2)

C++:运行时间12ms,45.24%,空间10.9M,42.1%:

class Solution { public: int minPathSum(vector<vector<int>>& grid) { int rows = grid.size(); int cols = grid[0].size(); vector<vector<int>> dp(rows, vector<int>(cols, grid[0][0])); for (int i = 1; i < rows; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } for (int j = 1; j < cols; j++) { dp[0][j] = dp[0][j - 1] + grid[0][j]; } for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; } } return dp[rows - 1][cols - 1]; } };

这里还学会了二维vector初始化的方法:vector<vector<int>> dp(rows, vector<int>(cols, grid[0][0]));

2020.8.18补Java:

Runtime: 3 ms, faster than 47.06% of Java online submissions for Minimum Path Sum.

Memory Usage: 43.7 MB, less than 8.50% of Java online submissions for Minimum Path Sum.

class Solution { public int minPathSum(int[][] grid) { int rows = grid.length; int cols = grid[0].length; int[][] dp = new int[rows][cols]; dp[0][0] = grid[0][0]; for (int i = 1; i < cols; i++) { dp[0][i] = dp[0][i - 1] + grid[0][i]; } for (int i = 1; i < rows; i++) { dp[i][0] = dp[i - 1][0] + grid[i][0]; } for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { dp[i][j] = Math.min(dp[i - 1][j] + grid[i][j], dp[i][j - 1] + grid[i][j]); } } return dp[rows - 1][cols - 1]; } }

看了discussion发现上面的二维数组还可以优化空间复杂度,只需要用到O(n)。因为每次更新dp[i][j]的时候,我们只需要拥有它左边的那个元素和它上方的元素。因此,我们可以只定义一个vector用来存当前遍历的这一列,每次更新的时候根据上次的更新第一行,后面的就跟它左边和上面的元素进行比较即可(但是这里之前浪费了好长时间不太知道该怎么写)。时间8ms,87.52%,空间10.2M,100%:

class Solution { public: int minPathSum(vector<vector<int>>& grid) { int rows = grid.size(); int cols = grid[0].size(); vector<int> curr(rows, grid[0][0]); for (int i = 1; i < rows; i++) { curr[i] = curr[i - 1] + grid[i][0]; } for (int j = 1; j < cols; j++) { curr[0] += grid[0][j]; for (int i = 1; i < rows; i++) { curr[i] = min(curr[i - 1], curr[i]) + grid[i][j]; } } return curr[rows - 1]; } };

2020.8.18补Java:不知道为啥去年说不知道该怎么写,这次倒是看完优化思路以后马上就写出来了,但是有一个小坑卡了一下下,就是那个双重循环里的i和j的顺序问题。

Runtime: 4 ms, faster than 25.99% of Java online submissions for Minimum Path Sum.

Memory Usage: 43 MB, less than 34.28% of Java online submissions for Minimum Path Sum.

class Solution { public int minPathSum(int[][] grid) { int rows = grid.length; int cols = grid[0].length; int[] dp = new int[rows]; dp[0] = grid[0][0]; for (int i = 1; i < rows; i++) { dp[i] = dp[i - 1] + grid[i][0]; } for (int i = 1; i < cols; i++) { for (int j = 0; j < rows; j++) { if (j == 0) { dp[j] += grid[j][i]; } else { dp[j] = Math.min(dp[j - 1] + grid[j][i], dp[j] + grid[j][i]); } } } return dp[rows - 1]; } }

对于亚麻那道题:https://leetcode.com/discuss/interview-question/383669/

Given a matrix with r rows and c columns, find the maximum score of a path starting at [0, 0] and ending at [r-1, c-1]. The score of a path is the minimum value in that path. For example, the score of the path 8 → 4 → 5 → 9 is 4.

Don't include the first or final entry. You can only move either down or right at any point in time.

Example 1:

Input: [[5, 1], [4, 5]] Output: 4 Explanation: Possible paths: 5 → 1 → 5 => min value is 1 5 → 4 → 5 => min value is 4 Return the max value among minimum values => max(4, 1) = 4.

Example 2:

Input: [[1, 2, 3] [4, 5, 1]] Output: 4 Explanation: Possible paths: 1-> 2 -> 3 -> 1 1-> 2 -> 5 -> 1 1-> 4 -> 5 -> 1 So min of all the paths = [2, 2, 4]. Note that we don't include the first and final entry. Return the max of that, so 4.

亚麻这道题要求的是,一个path的score定义为这个path里最小的值,要求所有path的score里的最大的,题目比较绕。还是采用类似的DP的方法,先把第一行和第一列给赋值好,然后对后面的dp[i][j],状态转移方程采用:dp[i][j] = max(min(dp[i - 1][j], grid[i][j]), min(dp[i][j - 1], grid[i][j])),相当于就是一个dp二维矩阵中的元素,采用到它的两个路径中上一个节点和它自己比较的较小值(也就是到这一个元素的score)中的较大的(也就是更大的score),另外注意第一个节点和最后一个节点是不算数的,因此要特殊处理一下。代码:

// Given a matrix with r rows and c columns, find the maximum score of a path starting at [0, 0] and ending at [r - 1, c - 1]. The score of a path is the minimum value in that path. For example, the score of the path 8 → 4 → 5 → 9 is 4. #include <iostream> #include <string> #include <vector> #include <limits.h> using namespace std; int maxScore(vector<vector<int> >& grid){ int rows = grid.size(); int cols = grid[0].size(); vector<vector<int>> dp(rows, vector<int>(cols, grid[0][0])); dp[0][1] = grid[0][1]; dp[1][0] = grid[1][0]; for (int i = 2; i < rows; i++) { dp[i][0] = min(dp[i - 1][0], grid[i][0]); } for (int i = 2; i < cols; i++) { dp[0][i] = min(dp[0][i - 1], grid[0][i]); } for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { if (!((i == rows - 1) && (j == cols - 1))) { dp[i][j] = max(min(grid[i][j], dp[i - 1][j]), min(grid[i][j], dp[i][j - 1])); } else { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } } return dp[rows - 1][cols - 1]; //return 0; } int main() { // Testing vector<vector<int>> grid1 {{5, 1}, {4, 5}}; vector<vector<int> > grid0 {{1, 2, 3}, {4, 5, 1}}; vector<vector<int> > grid2 {{5, 1, 7}, {4, 8, 5}}; vector<vector<int> > grid3 {{1, 9, 9}, {9, 9, 9}, {9, 9, 9}}; vector<vector<int> > grid4 {{10, 7, 3}, {12, 11, 9}, {1, 2, 8}}; vector<vector<int> > grid5 {{20, 20, 3}, {20, 3, 20}, {3, 20, 20}}; cout << "Max score should be 4: " << maxScore(grid1) << "\n"; cout << "Max score should be 4: " << maxScore(grid0) << "\n"; cout << "Max score should be 4: " << maxScore(grid2) << "\n"; cout << "Max score should be 9: " << maxScore(grid3) << "\n"; cout << "Max score should be 9: " << maxScore(grid4) << "\n"; cout << "Max score should be 3: " << maxScore(grid5) << "\n"; }

Java:

public class MaxMinScore { public static int maxMinScore(int[][] matrix) { int rows = matrix.length; int cols = matrix[0].length; int[][] dp = new int[rows][cols]; dp[0][0] = Integer.MAX_VALUE; for (int i = 1; i < rows; i++) { dp[i][0] = Math.min(dp[i - 1][0], matrix[i][0]); } for (int i = 1; i < cols; i++) { dp[0][i] = Math.min(dp[0][i - 1], matrix[0][i]); } for (int i = 1; i < rows; i++) { for (int j = 1; j < cols; j++) { if (i == rows - 1 && j == cols - 1) { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } else { dp[i][j] = Math.max(Math.min(matrix[i][j], dp[i - 1][j]), Math.min(matrix[i][j], dp[i][j - 1])); } } } return dp[rows - 1][cols - 1]; } public static void main(String[] args) { int[][] matrix1 = {{5, 1}, {4, 5}}; int[][] matrix2 = {{1, 2, 3}, {4, 5, 1}}; int[][] matrix3 = {{5, 1, 7}, {4, 8, 5}}; int[][] matrix4 = {{1, 9, 9}, {9, 9, 9}, {9, 9, 9}}; int[][] matrix5 = {{10, 7, 3}, {12, 11, 9}, {1, 2, 8}}; int[][] matrix6 = {{20, 20, 3}, {20, 3, 20}, {3, 20, 20}}; System.out.println("should be 4: " + maxMinScore(matrix1)); System.out.println("should be 4: " + maxMinScore(matrix2)); System.out.println("should be 4: " + maxMinScore(matrix3)); System.out.println("should be 9: " + maxMinScore(matrix4)); System.out.println("should be 9: " + maxMinScore(matrix5)); System.out.println("should be 3: " + maxMinScore(matrix6)); } }

 

最新回复(0)