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.
题目:
在一个m行n列的二维数组中,每个元素都是非负数,从左上角走到右下角,每次只能向右或向下走,求该路径的总和最小。
思路:
1、枚举
枚举所有路径,从左上角到右下角,共经过m+n-2步,其中向下走m-1步,向右走n-1步,因此所有可能路径数为C(m+n-2,m-1),算出所有路径的总和,找出最小的。
暴力枚举是万能的,但是不实际。
2、动态规划
假设dp[i][j]表示从左上角走到(i,j)的路径最小总和,因为每一步只能往下或往右,因此可以从左边(i-1,j)或上边(i,j-1)走到(i,j)。
状态转移方程:
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+A[i][j]
初始值:
dp[0][0]=A[0][0],
dp[i][0]=dp[i-1][0]+A[i][0],
dp[0][j]=dp[0][j-1]+A[0][j].
复杂度:
时间复杂度O(m*n),空间复杂度O(m*n)
空间优化:
dp[i][j]=min(dp[i-1][j],dp[i][j-1]),只与dp[i-1][j],dp[i][j-1]有关,可以去掉一维,只剩下
dp[j]=min(dp[j],dp[j-1]),因为等号右边的dp[j]是旧的,即dp[i-1][j],等号右边的dp[j-1]是新的,即dp[i][j-1](从循环i,j中可以明显看出来)
代码:
class Solution { public: int minPathSum(vector<vector<int>>& grid) { int m=grid.size(); int n=grid[0].size(); vector<vector<int> > dp(m,vector<int>(n,0)); for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ if(i==0){ if(j==0) dp[i][j]=grid[i][j]; else dp[i][j]=dp[i][j-1]+grid[i][j]; } else if(j==0) dp[i][j]=dp[i-1][j]+grid[i][j]; else dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]; } } return dp[m-1][n-1]; } };
class Solution { public: int minPathSum(vector<vector<int>>& grid) { int m=grid.size(); int n=grid[0].size(); vector<int> dp(n,0); for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ if(i==0){ if(j==0) dp[j]=grid[i][j]; else dp[j]=dp[j-1]+grid[i][j]; } else if(j==0) dp[j]=dp[j]+grid[i][j]; else dp[j]=min(dp[j],dp[j-1])+grid[i][j]; } } return dp[n-1]; } };