LeetCode/最小路径和
给定一个包含非负整数的m×n网格grid,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
1. 动态规划
将问题转化成子问题的方程(递归重复计算耗时过多,以后不再使用反向递归)
状态转移函数:最小路径长度dp[m][n]=min(dp[m-1][n],dp[m][n-1])+grid[m][n]
边界条件:dp[i][0]=0、dp[0][i]=0
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.size() == 0 || grid[0].size() == 0) return 0;
int rows = grid.size(), columns = grid[0].size();//得到行数和列数
auto dp = vector < vector <int> > (rows, vector <int> (columns));//初始化dp数组
dp[0][0] = grid[0][0];//边界
//!!!由于实际使用中数组零下标存放了数据,不能用于初始化边界0,故直接算出两条存有数据的新边界
for (int i = 1; i < rows; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];//算出第一列路径长度(边界)
}
for (int j = 1; j < columns; j++) {
dp[0][j] = dp[0][j - 1] + grid[0][j];//算出第一行路径长度(边界)
}
for (int i = 1; i < rows; i++) {
for (int j = 1; j < columns; j++) {//一行一行或一列一列从前往后算都可以
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[rows - 1][columns - 1];
}
};
2. 动态规划一维优化
由于必须要遍历整个grid二维数组,才能得出最小路径,时间复杂度最小为O(n2),无法再进行优化
仔细观察方法一,发现进行参数更新的时候,只与前一列(行)同位置元素有关,更新后之前的数据就没用了
所以我们可以用一维数组对dp进行存储,只是要注意参数更新时候的位置,可以使空间复杂度减小为O(n)
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
if (grid.size() == 0 || grid[0].size() == 0) return 0;
int rows = grid.size(), columns = grid[0].size();//得到行数和列数
vector<int> dp(columns); //一维数组存储一行的数据
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {//一行一行进行参数更新
if(i==0&&j==0)
dp[j]=grid[i][j]; //初始点赋原值
else if(i==0&&j!=0) //第一行的参数更新
dp[j]=grid[i][j]+dp[j-1];
else if(i!=0&&j==0) //第一列的参数更新情况发生变化,因为前面没参数
dp[j]=grid[i][j]+dp[j];//只能由上一行进行转移
else //既能由上转移又能由左转移的情况
dp[j] = min(dp[j-1], dp[j]) + grid[i][j];
}
}
return dp[columns - 1];
}
};
3. 回溯法
相当于使用深度优先的方式,通过递归右和下方向,遍历所有路径,同一个节点被多条路径重复遍历,时间复杂度非常高
事前要声明全局变量最小路径和,以便不同路径比较得出最小路径,这里给出一个框架
点击查看代码
int min_sum = INT_MAX;//全局变量赋一个极大值
void dfs(vector<vector<int>>& grid,int row,int col,int sum){
if(超出递归边界) return;
sum+=grid(row,col); //路径权值加入路径和
if(达到路径终点) {
min_sum = min(min_sum,sum);
return;
}
dfs(grid,row+1,col,sum);//递归往右移动
//跳出递归后相当于取消向右移动,进行了一次回溯
dfs(grid,row,col+1,sum);//递归往下移动
}