夜深人静刷力扣

最近在刷动态规划的题目,跟着大佬“代码随想录”的pdf在刷力扣上的题目。碰到了一个动态规划的题目,于是将它记录了下来。

题目链接:https://leetcode-cn.com/problems/unique-paths/

我根据pdf学会了三种解题方法,分别是二叉树的遍历(把各个叶子节点找出),动态规划(二维数组的优点是思路清楚,一目了然。一维数组的优点是大大减少了空间复杂度),数论(组合的方法,不过要注意int类型相乘的时候会溢出,要做到边乘边除)。

  下面我来详细的叙述各种方法,并附上代码

题目如图所示:

 首先我要讲述的是二叉树的遍历的方法,这里的知识需要用的数据结构。没学数据结构的童鞋请参考B站《王道考研数据结构》。不说了上代码


class Solution {
public:
int dfs(int i,int j,int m,int n){
    if(i>m||j>n)return 0;//这一步不能缺省
    if(i==m&&j==n)return 1;//递归的边界
    else return dfs(i+1,j,m,n)+dfs(i,j+1,m,n);
}
    int uniquePaths(int m, int n) {
return dfs(1,1,m,n);
    }
};

这里由于要遍历整个叶子节点,时间复杂度将是指数的形式,故不可取。

第二种方法是动态规划,首先我们讲解用二维数组的方法来动态规划。

最近在“代码随想录”pdf里面学到了动态规划五部曲

1.确定dp数组

2.确定递推公式

3.边界的初始化

4.确定遍历顺序

5.举例推导dp数组

 那么我们先来看动态规划(二维数组的实现)

class Solution {
public:
    int uniquePaths(int m, int n) {
//创建dp[m][n],代表走到第m行,n列的所有路径
vector<vector<int>>dp(m,vector<int>(n,0));
//初始化边界
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=1;i<m;i++){
    for(int j=1;j<n;j++){
        dp[i][j]=dp[i-1][j]+dp[i][j-1];
    }
}
return dp[m-1][n-1];
    }
};

我们再来试着用动态规划(一维数组的实现),实际上就是把二维数组的j省略了

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<int>dp(m);
//这里相当于J=0时的初始化
for(int i=0;i<m;i++){
    dp[i]=1;
}
for(int j=1;j<n;j++){
    for(int i=1;i<m;i++){
        dp[i]+=dp[i-1];
    }
}
return dp[m-1];
    }
};

那么最后我们看看数论(排列组合的方法):从m+n-2个数中选m-1个数

组合数公式如图

 

class Solution {
public:
    int uniquePaths(int m, int n) {
 int numerator=1;
 int demunator=1;
 int count=m-1;
 int t=m+n-2;
 while(count--)numerator*=(t--);
 for(int i=1;i<=m-1;i++)demunator*=i;
 return numerator/demunator;
    }
};

 

 但是这种方法提交的话会出现“溢出”(两个int类型相乘)

Line 8: Char 25: runtime error: signed integer overflow: 1764322560 * 10 cannot be represented in type 'int' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:17:25

 解决方法是做到边乘边除。

class Solution {
public:
 int uniquePaths(int m, int n) {
 long long numerator = 1; // 分⼦
 int denominator = m - 1; // 分⺟
 int count = m - 1;
 int t = m + n - 2;
 while (count--) {
 numerator *= (t--);
 while (denominator != 0 && numerator % denominator == 0) {
 numerator /= denominator;
 denominator--;
 }
 }
 return numerator;
 }
};

 好了,终于把这道题叙述完了。

已知乾坤大,犹怜草木青。这里北风,星河辽阔,一路相伴。

 

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值