3.二维动态规划
1)
力扣https://leetcode.cn/problems/minimum-path-sum/第一行的的路径只与左边的元素有关,第一列的路径只与上面的元素有关。
除了第一行和第一列,其他元素的路径取决于左边和上面元素的最小值。
只要每次都选择值最小的路径,最后得到的就是最小路径。
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
vector<vector<int>> path = grid;
for(int i=1;i<n;i++){
path[0][i] += path[0][i-1];
}
for(int i=1;i<m;i++){
path[i][0] += path[i-1][0];
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
path[i][j] += min(path[i-1][j], path[i][j-1]);
}
}
return path[m-1][n-1];
}
};
上述代码用到了二维数组,为了空间压缩,可以只用一个一维数组:
path[j]表示二维数组中的path[i-1][j](未更新)
path[j-1]表示二维数组中的path[i][j-1](已更新)
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m = grid.size();
int n = grid[0].size();
vector<int> path(n,0);
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(i==0&&j==0){
path[j] = grid[i][j];
}else if(i==0){
path[j] = path[j-1] + grid[i][j];
}else if(j==0){
path[j] = path[j] + grid[i][j];
}else{
path[j] = min(path[j],path[j-1]) + grid[i][j];
}
}
}
return path[n-1];
}
};
2)
力扣https://leetcode.cn/problems/01-matrix/当元素值为0时,最近距离就是0。
当元素值为1时,最近距离为周围四个元素的最近距离的最小值加1。
因为做BFS,最差时间复杂度为O(m*n*m*n)。
所以还是用DP记录最近距离速度会更快些。
很直观地能发现,先从左上往右下扫描,得到只考虑左边元素和上边元素时的最小距离。
再从右下往左上扫描,可以得到考虑右边元素和下边元素的最小距离。
做完两遍扫描,就把周围四个元素都考虑进去了。
时间复杂度为O(2*m*n)。
注意最小距离数组一开始要设置为最大距离减一
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size();
vector<vector<int>> res(m,vector<int>(n,INT_MAX-1));
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(mat[i][j]==0){
res[i][j] = 0;
}else{
if(i>0){
res[i][j] = min(res[i][j], res[i-1][j]+1);
}
if(j>0){
res[i][j] = min(res[i][j], res[i][j-1]+1);
}
}
}
}
for(int i=m-1;i>=0;i--){
for(int j=n-1;j>=0;j--){
if(res[i][j]){
if(i<m-1){
res[i][j] = min(res[i][j], res[i+1][j]+1);
}
if(j<n-1){
res[i][j] = min(res[i][j], res[i][j+1]+1);
}
}
}
}
return res;
}
};
3)
力扣https://leetcode.cn/problems/maximal-square/假设当前元素是正方形右下角的元素
若想要正方形边长为1,那么当前元素值为'1'就行了
若想要正方形变成为2,那么不仅要当前元素值为’1‘,还需要上边,左边,左上角三个元素分别所能构成的最大正方形边长>=1。
若想要正方形变成为3,那么不仅要当前元素值为’1‘,还需要上边,左边,左上角三个元素分别所能构成的最大正方形边长>=2。
依此类推,得到状态转移方程:
dp[i][j] = 1 + min(dp[i-1][j],min(dp[i][j-1], dp[i-1][j-1]))
每次记录边长最长的值,最终就能得到最大正方形的面积。
class Solution {
public:
int maximalSquare(vector<vector<char>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int res = 0;
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||j==0){
dp[i][j] = matrix[i][j]-'0';
res = max(res, dp[i][j]);
}else{
if(matrix[i][j]=='1'){
dp[i][j] = 1 + min(dp[i-1][j],min(dp[i][j-1], dp[i-1][j-1]));
res = max(res, dp[i][j]);
}
}
}
}
return res*res;
}
};