[leetcode] UniquePathsI, II, III

UniquePaths

  • 问题描述:给定一个起点和终点,找到一共有多少条满足条件的路径。
Unique Paths I
  • 给定一个矩阵,起点在左上角,终点在右下角。只能向下走或者向右走。
  • 思路:我们当然可以用DFS来做,但是时间复杂度就是 O ( 2 ( M ∗ N ) ) O(2^{(M*N)}) O(2(MN))。所以我们采用动态规划的方法来做。
    • 转移方程如下: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] = dp[i-1][j] + dp[i][j-1] dp[i][j]=dp[i1][j]+dp[i][j1]
    • 初始化: d p [ 0 : i ] [ 0 ] = 1 , d p [ 0 ] [ 0 : j ] = 1 dp[0:i][0] = 1, dp[0][0:j] = 1 dp[0:i][0]=1,dp[0][0:j]=1
  • 代码:
int uniquePaths(int m, int n) {
        int res = 0;
//        bool visits[m * n];
//        memset(visits, false, sizeof(visits));
//        uniquePathsRecursive(m, n, 0, 0, visits, res);
        int dp[m][n];
        for(int i=0;i<m;i++){
            dp[i][0] = 1;
        }
        for(int j=0;j<n;j++){
            dp[0][j] = 1;
        }
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i == 0 || j == 0)
                    continue;
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        res = dp[m-1][n-1];
        return res;
    }
Unique Paths II
  • 给定一个矩阵,起点在左上方,终点在右下方,路径上还有一些点不能走,用1表示。只能走下或右。计算有多少不同的路径。
  • 思路:还是动态规划的想法,相比于I,我们更改一个条件:如果当前位置不可走,则dp[i][j] =0;
    • 转移方程如下: d p [ i ] [ j ] = ( d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] ) ∗ ( g r i d [ i ] [ j ] = = 0 ) dp[i][j] = (dp[i-1][j] + dp[i][j-1]) * (grid[i][j] == 0) dp[i][j]=(dp[i1][j]+dp[i][j1])(grid[i][j]==0)
    • 初始化
      • dp[0][0] = grid[0][0] == 0;
      • dp[i][0] = dp[i-1][0] && grid[i][0] == 0
      • dp[0][j] = dp[0][j-1] && grid[0][j] == 0
  • 代码:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        int m = (int) obstacleGrid.size();
        if(m == 0)
            return 0;
        int n = (int) obstacleGrid[0].size();
        //cout<<m<<", "<<n<<endl;
        long long dp[m][n];
        memset(dp, 0, sizeof(dp));
        if(obstacleGrid[0][0] != 0)
            return 0;
        dp[0][0] = 1;
        for(int i=1;i<m;i++){
            if(obstacleGrid[i][0] == 0 && dp[i-1][0] == 1){
                dp[i][0] = 1;
            }else{
                dp[i][0] = 0;
            }
        }
        for(int j=1;j<n;j++){
            if(obstacleGrid[0][j] == 0 && dp[0][j-1] == 1){
                dp[0][j] = 1;
            }else{
                dp[0][j] = 0;
            }
        }
        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                if(obstacleGrid[i][j] == 0)
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                else
                    dp[i][j] = 0;
            }
        }
        return dp[m-1][n-1];
    }
Unique Paths III
  • 给定一个矩阵,0表示可以走,1表示起点,2表示终点,-1表示障碍物。此时可以向四个方向走。问从起点到终点,将所有可以路过的点路过有且只有一次的走法有多少种。
  • 思路
    • DFS是一种,我们首先计算出完整的路径我们一共要走的步数,以及起始点和终点的坐标。然后我们有以下终止条件:
      • 如果步数达标
        • 当前点是终点,res += 1
        • 否则,return
      • 如果当前点是终点,步数没达标
        • return
    • 动态规划也是一种思路。
    • 整体来说动态规划的思路和DFS比较相似。在leetcode上两者的耗时也基本一致。如下图所示。
      在这里插入图片描述
  • 代码:
class Solution {
public:
    bool isVaild(int x, int y, int m, int n){
        if(x>=0 && x<m && y>=0 && y<n){
            return true;
        }
        return false;
    }
    int dxs[4] = {1, 0, -1, 0};
    int dys[4] = {0, 1, 0, -1};
    void uniquePathsIIIRecursive(const vector<vector<int>>& grid, int m, int n, int x, int y, int step,
            int total_step, bool* visits, int& res){
        // cout<<x<<", "<<y<<endl;
        if(step == total_step){
            if(grid[x][y] == 2)
                res += 1;
            return;
        }
        if(grid[x][y] == 2){
            return;
        }
        for(int dir_id=0;dir_id<4;dir_id++){
            int new_x = x + dxs[dir_id];
            int new_y = y + dys[dir_id];
            if(isVaild(new_x, new_y, m, n)){
                int visit_pos = new_x * n + new_y;
                if(!visits[visit_pos] && grid[new_x][new_y] != -1){
                    visits[visit_pos] = true;
                    uniquePathsIIIRecursive(grid, m, n, new_x, new_y, step + 1, total_step, visits, res);
                    visits[visit_pos] = false;
                }
            }
        }
    }
    int uniquePathsIII(vector<vector<int>>& grid) {
        int m = (int) grid.size();
        if(m == 0){
            return 0;
        }
        int n = (int) grid[0].size();
        bool visits[m * n];
        memset(visits, false, sizeof(visits));
        int total_step = 0;
        int start_x = 0;
        int start_y = 0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(grid[i][j] == 0 || grid[i][j] == 2){
                    total_step += 1;
                }
                if(grid[i][j] == 1){
                    start_x = i;
                    start_y = j;
                }
            }
        }
        int res = 0;
        visits[start_x * n + start_y] = true;
        uniquePathsIIIRecursive(grid, m, n, start_x, start_y, 0, total_step, visits, res);
        return res;
    }
    int code(int x, int y, int m, int n){
        return 1 << (x * n + y);
    }
    int uniquePathsIII_V2(vector<vector<int>>& grid) {
        int m = (int) grid.size();
        if(m == 0){
            return 0;
        }
        int n = (int) grid[0].size();
        int start_x;
        int start_y;
        int target_x;
        int target_y;
        int target = 0;
        for(int i=0;i<m;i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 0) {
                    target |= code(i, j, m, n);
                } else {
                    if (grid[i][j] == 1) {
                        start_x = i;
                        start_y = j;
                    } else {
                        if (grid[i][j] == 2) {
                            target |= code(i, j, m, n);
                            target_x = i;
                            target_y = j;
                        }
                    }
                }
            }
        }
        return dp(start_x, start_y, m, n, target_x, target_y, target);
    }
    int dp(int x, int y, int m, int n, int target_x, int target_y, int to_do){
        if(to_do == 0){
            if(x == target_x && y == target_y)
                return 1;
            return 0;
        }
        if(x == target_x && y == target_y)
            return 0;
        int ans = 0;
        for(int i=0;i<4;i++){
            int new_x = x + dxs[i];
            int new_y = y + dys[i];
            if(isVaild(new_x, new_y, m, n)){
                if(to_do & code(new_x, new_y, m, n))
                    ans += dp(new_x, new_y, m, n, target_x, target_y, to_do ^ code(new_x, new_y, m, n));
            }
        }
        return ans;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值