【Unique Paths】cpp

题目:

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?

Above is a 3 x 7 grid. How many possible unique paths are there?

Note: m and n will be at most 100.

代码:

复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
            int dp[m][n];
            memset(dp, 0, sizeof(dp));
            for ( size_t i = 0; i < n; ++i ) dp[0][i] = 1;
            for ( size_t i = 0; i < m; ++i ) dp[i][0] = 1;
            for ( size_t i = 1; i < m; ++i )
            {
                for ( size_t j = 1; j < n; ++j )
                {
                    dp[i][j] = dp[i-1][j] + dp[i][j-1];
                }
            }
            return dp[m-1][n-1];
    }
};
复制代码

tips:

常规dp解法。

=====================================

上面的代码有可以改进的地方:dp[m][n]并不用这些额外空间,只需要两个长度为n的数组即可;一个保存前一行的状态,一个用于遍历当前行的状态,每次滚动更新,可以省去额外空间。沿着上述思路改进了一版代码如下:

 

复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
            int curr[n], pre[n];
            for ( size_t i = 0; i<n; ++i ) { pre[i]=1; curr[i]=0; }
            curr[0] = 1;
            for ( size_t i = 1; i<m; ++i )
            {
                for ( size_t j = 1; j<n; ++j )
                {
                    curr[j] = curr[j-1] + pre[j];
                    pre[j] = curr[j];
                }
                curr[0] = 1;
            }
            return pre[n-1];
    }
};
复制代码

这个代码空间复杂度降到了O(n),但还是可以改进。其实只用一个一维的数组dp就可以了,代码如下。

复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
            int curr[n];
            memset(curr, 0, sizeof(curr));
            curr[0] = 1;
            for ( size_t i = 0; i < m; ++i )
            {
                for ( size_t j = 1; j < n; ++j )
                {
                    curr[j] = curr[j-1] + curr[j];
                }
            }
            return curr[n-1];
    }
};
复制代码

这里用到了滚动数组的技巧。有个细节需要注意,外层dp是可以从0行开始,省去了一部分代码。

=====================================

再学一种深搜+缓存(即“备忘录”)解法。

复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
            vector<vector<int> > cache(m+1,vector<int>(n+1,0));
            return Solution::dfs(m, n, cache);
    }
    static int dfs( int x, int y, vector<vector<int> >& cache )
    {
            if ( x<1 || y<1 ) return 0;
            if ( x==1 && y==1 ) return 1;
            int left = cache[x-1][y]>0 ? cache[x-1][y] : cache[x-1][y]=Solution::dfs(x-1, y, cache);
            int up = cache[x][y-1]>0 ? cache[x][y-1] : cache[x][y-1]=Solution::dfs(x, y-1, cache);
            return left+up;
    }
};
复制代码

有点儿类似动态规划的思想:开一个cache数组保存已经深搜遍历过的中间结果,避免重复遍历。

这里有个简化代码的技巧:定义cache的时候多定义一行和一列,这样在深搜的过程中按照dfs中的代码可以省去判断cache下标是否越界的逻辑。

===============================================

第二次过这道题,直接写了一个dp的做法。

复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
            int dp[m][n];
            fill_n(&dp[0][0], m*n, 0);
            for ( int i=0; i<n; ++i ) dp[0][i]=1;
            for ( int i=0; i<m; ++i ) dp[i][0]=1;
            for ( int i=1; i<m; ++i )
            {
                for ( int j=1; j<n; ++j )
                {
                    dp[i][j] = dp[i][j-1] + dp[i-1][j];
                }
            }
            return dp[m-1][n-1];
    }
};
复制代码

 

posted on   承续缘  阅读(200)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示