Lintcode 1543 · Unique Path IV (DP 好题)

文章讨论了如何使用动态规划算法解决一个关于在给定高度和宽度的网格中找到从左上角到右下角独特路径数量的问题,提供了两种方法,一种是逆推,另一种是正向推进,并给出了优化版本以减少空间复杂度。

1543 · Unique Path IV
Algorithms
Description
Solution14
Notes
Discuss26
Leaderboard
Record

Description
Give two integers to represent the height and width of the grid. The starting point is in the upper left corner and the ending point is in the upper right corner. You can go to the upper right corner, right or lower right corner. Find out the number of paths you can reach the end. And the result needs to mod 1000000007.

width > 1, height > 1

Example
Example 1:

Input:
height = 3
width = 3
Output:
2
Explanation: There are two ways from start to end.

image

Example 2:

Input:
height = 2
weight = 2
Output:
1
Explanation: There are only one way from (1,1) to (2,1)

解法1:
反过来逆推,从右上角开始,那么行要从上到下,列要从右到左。
注意:很重要的一点是列要放在外循环
以5行4列矩阵为例,a[0][4]为终点,dp[0][4]=1。那么其相邻的dp[0][3]=1, dp[1,3]=1,dp[1][4]=0。
如果行循环在外面,那么列会先更新,dp[0][3]=1,dp[0][2]=1,…。我们可以看到dp[0][3]先于dp[1][4]更新,但实际上dp[0][3]应该后于dp[1][4]。

class Solution {
public:
    /**
     * @param height: the given height
     * @param width: the given width
     * @return: the number of paths you can reach the end
     */
    int uniquePath(int height, int width) {
        #define MOD 1000000007
        if (height == 0 || width == 0) return 1;
        vector<vector<int>> dp(height, vector<int>(width, 0));
        dp[0][width - 1] = 1;
        for (int j = width - 1; j >= 0; j--) {   //注意列在先。因为
            for (int i = 0; i < height; i++) {
                if (j - 1 >= 0) {
                    if (i + 1 < height) {
                        dp[i + 1][j - 1] = (dp[i + 1][j - 1] + (dp[i][j] % MOD)) % MOD;
                    }
                    dp[i][j - 1] = (dp[i][j - 1] + (dp[i][j] % MOD)) % MOD;
                    if (i - 1 >= 0) {
                        dp[i - 1][j - 1] = (dp[i - 1][j - 1] + (dp[i][j] % MOD)) % MOD;
                    }

                }
            }
        }
        return dp[0][0] % MOD;
    }
};

解法2:正向推。注意:很重要的一点也是列要放在外循环

class Solution {
public:
    /**
     * @param height: the given height
     * @param width: the given width
     * @return: the number of paths you can reach the end
     */
    int uniquePath(int height, int width) {
        #define MOD 1000000007
        if (height == 0 || width == 0) return 1;
        vector<vector<int>> dp(height, vector<int>(width, 0));
        dp[0][0] = 1;
        for (int j = 0; j < width; j++) {
            for (int i = 0; i < height; i++) {
                if (j - 1 >= 0) {
                    dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
                    if (i - 1 >= 0) {
                        dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MOD;
                    }
                    if (i + 1 < height) {
                        dp[i][j] = (dp[i][j] + dp[i + 1][j - 1]) % MOD;
                    }
                }
            }
        }
        return dp[0][width - 1];
    }
};

上面的if (j-1>=0)可以简化

class Solution {
public:
    /**
     * @param height: the given height
     * @param width: the given width
     * @return: the number of paths you can reach the end
     */
    int uniquePath(int height, int width) {
        #define MOD 1000000007
        if (height == 0 || width == 0) return 1;
        vector<vector<int>> dp(height, vector<int>(width, 0));
        dp[0][0] = 1;
        for (int j = 1; j < width; j++) {
            for (int i = 0; i < height; i++) {
                dp[i][j] = (dp[i][j] + dp[i][(j - 1)]) % MOD; //也可以直接写成dp[i][j] = dp[i][(j - 1)] % MOD;
                if (i - 1 >= 0) {
                    dp[i][j] = (dp[i][j] + dp[i - 1][(j - 1)]) % MOD;
                }
                if (i + 1 < height) {
                    dp[i][j] = (dp[i][j] + dp[i + 1][(j - 1)]) % MOD;
                }
            }
        }
        return dp[0][(width - 1)];
    }
};

加上滚动数组优化:

class Solution {
public:
    /**
     * @param height: the given height
     * @param width: the given width
     * @return: the number of paths you can reach the end
     */
    int uniquePath(int height, int width) {
        #define MOD 1000000007
        if (height == 0 || width == 0) return 1;
        vector<vector<int>> dp(height, vector<int>(2, 0));
        dp[0][0] = 1;
        for (int j = 1; j < width; j++) {
            for (int i = 0; i < height; i++) {
                dp[i][j % 2] = dp[i][(j - 1) % 2] % MOD;   //注意这里不能用 dp[i][j%2] = (dp[i][j%2] + dp[i][(j - 1)%2]) % MOD; 因为dp[i][j%2]会跟之前的值混淆。如果不用滚动数组可以
                if (i - 1 >= 0) {
                    dp[i][j % 2] = (dp[i][j % 2] + dp[i - 1][(j - 1) % 2]) % MOD;
                }
                if (i + 1 < height) {
                    dp[i][j % 2] = (dp[i][j % 2] + dp[i + 1][(j - 1) % 2]) % MOD;
                }
            }
        }
        return dp[0][(width - 1) % 2];
    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值