文章目录
- 62. 不同路径
- 题意
- 解法1 排列组合
- 解法2 动态规划
 
- 64. 最小路径和
- 题意
- 解法1 DFS(剪枝也超时)
- 解法2 动态规划
 
62. 不同路径
题意
- 一道数学题,排列组合/小学奥赛题。
- 动态规划不是一般来解决最值问题的吗,这道题为什么会想到dp?
解法1 排列组合
从左上角到右下角,一共要走m+n-2步,其中向右n-1步,向下m-1步,因此路径的总数,相当于从m+n-2中选择m-1个向下的步数,即排列组合。
 
- 但是,需要注意的是,题目只保证最后结果在int型范围内,而实际上如果按下面的代码运行,即便中间运算已经用long long存储,还是会溢出,所以需要一边乘一边除(即便是一边乘一边除,中间过程也必须用long long,否则中间计算会超出int型可表示范围)。
class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans=1;
        for(int i=n;i<=m+n-2;i++)
            ans=ans*i; 	//会溢出
        for(int i=1;i<m;i++)
            ans/=i;
        return ans;
    }
};
// ac代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans=1;
        for(int i=n,j=1;i<=m+n-2;i++,j++)
            ans=ans*i/j;
        return ans;
    }
};
解法2 动态规划
- dp[i][j]表示走到 (i,j) 这个位置有几种走法。
- dp[i][j]=dp[i-1][j]+dp[i][j-1]。
- 注意dp[0][0]和边界情况(i-1和j-1)处理(也可以将dp[0,:]和dp[:,0]全置1)。
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int> > dp(m,vector<int>(n,0));
        dp[0][0]=1;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(dp[i][j]==0) 	//为了维护dp[0][0]
                {
                    int left=j==0?0:dp[i][j-1];
                    int top=i==0?0:dp[i-1][j];
                    dp[i][j]=left+top;
                }
            }
        }
        return dp[m-1][n-1];
    }
};
Attention
- 二维数组的定义
vector<vector<int>> asd1(row, vector<int>(column, 0)); //初始化row*column二维动态数组,初始化值为0
- 动态规划解法中,其实只需要保存dp[i-1][j]和dp[i][j-1]两个数,还有空间优化的余地。
- 排列组合基础
  
  
64. 最小路径和
题意
- 只能向右或向下走,约束很强,所以很好遍历!
- 求最小值。
- 和第62题有相似之处。
解法1 DFS(剪枝也超时)
建立一个队列q和一个数组value(记录每个点的最小值),将(0,0)压入队列,然后每从队列中取出一个点,就将其右和下两个点压入队列中,同时更新其右和下两个点的最小值。
但是由于超时,需要剪枝。所以只有当前点使得其右或下的点的最小值被更新时,才将这个点压入队列中。
但是依旧超时,,,
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        // m行n列
        int m=grid.size(),n=grid[0].size();
        vector<vector<int>> value(m,vector<int>(n,-1));
        queue<pair<int,int> > q;
        pair<int,int> st(0,0);
        q.push(st);
        value[0][0]=grid[0][0];
        while(!q.empty())
        {
            pair<int,int> tmp=q.front();
            q.pop();
            int x=tmp.first,y=tmp.second;
            if(x+1<m&&y<n)
            {
                int tmp_value=value[x][y]+grid[x+1][y];
                if(value[x+1][y]!=-1)
                {
                    if(tmp_value<=value[x+1][y])
                    {
                        value[x+1][y]=tmp_value;
                        pair<int,int> nxt(x+1,y);
                        q.push(nxt);
                    }
                }
                else
                {
                    value[x+1][y]=tmp_value;
                    pair<int,int> nxt(x+1,y);
                    q.push(nxt);
                }
                    
            }
            if(y+1<n&&x<m)
            {
                int tmp_value=value[x][y]+grid[x][y+1];
                if(value[x][y+1]!=-1)
                {
                    if(tmp_value<=value[x][y+1])
                    {
                        value[x][y+1]=tmp_value;
                        pair<int,int> nxt(x,y+1);
                        q.push(nxt);
                    }
                }
                else
                {
                    value[x][y+1]=tmp_value;
                    pair<int,int> nxt(x,y+1);
                    q.push(nxt);
                }
            }
        }
        return value[m-1][n-1];
    }
};
解法2 动态规划
和第62题不同的处理是,这里左边界和上边界的点要单独处理。最左列的点只能从它上面的点过来,而最上行的点只能从它左边过来。
其他没什么难点。
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        // m行n列
        int m=grid.size(),n=grid[0].size();
        vector<vector<int>> dp(m,vector<int>(n,-1));
        dp[0][0]=grid[0][0];
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(i==0&&j!=0)
                    dp[i][j]=dp[i][j-1]+grid[i][j];
                else if(j==0&&i!=0)
                    dp[i][j]=dp[i-1][j]+grid[i][j];
                else
                {
                    int left=j-1>=0?dp[i][j-1]:0;
                    int top=i-1>=0?dp[i-1][j]:0;
                    dp[i][j]=min(left+grid[i][j],top+grid[i][j]);
                }
            }
        }
        return dp[m-1][n-1];
    }
};
ATTENTION
- pair的用法:



















