动态规划——最短路径(代码随想录学习)

最短路径

题目描述:

    m×n的方格,每次移动的距离只能向右或者向下,起始位置到终止位置有多少种不同的路径?

start
end

 回顾知识:深度搜索、广度搜索

深度搜索:

 

  

广度搜索:

 第一种方法:深度搜索

由于只有向右和向下两种方法,将它们看做一棵二叉树的两个子树

有多少种不同路径就可以转化为有多少个叶子结点,即二叉树求叶子结点的个数

回顾知识:二叉树求叶子结点个数

判断左右孩子是否为空,找到叶子结点,递归调用函数

int BiTree(BiTree bt)
{
  if(bt==NULL) return 0;
  if(bt->lchild==NULL&&bt->rchild==NULL)
  return 1;
  return(BiTreeleaf(bt->lchild)+BiTreeleaf(bt->rchild));
}
代码:
class Solution
{
 private:
         int dfs(int i,int j,int m,int n)
         {
            if(i>m||j>n) return 0;//越界
            if(i==m&&j==n)return 1;
            return dfs(i+1,j,m,n)+dfs(i,j+1,m,n);
         }
 public:
        int uniquePaths(int m,int n)
        {
          return dfs(1,1,m,n)
        }
}

时间复杂度:

  二叉树的深度为m+n-1(深度按从1开始计算),二叉树的结点为2^(m+n-1)-1

超时!!!(最好复习一下类的知识)

第二种方法:动态规划

①dp数组含义

  二维矩阵定义一个二维数组dp[i][j]

dp[i][j]表示从[0,0]到[i,j]位置有多少种不同的路径

②递推公式

要想到达(i,j),根据题目要求(只能向下或者向右),则(i,j)是由dp[i-1][j]或者dp[i][j-1]

dp[i][j]= dp[i-1][j]+dp[i][j-1]

误解 :这里不应该是dp[i][j]=(dp[i-1][j]+1)+(dp[i][j-1]+1)?

这里是误解了dp[i][j]的含义,dp数组代表的是路径而不是步数,如果是步数要加一

③初始化dp数组

dp[i][j]的路径结果是由左边和上面推导而来的,所以初始化要首先初始化左边和上边的答案

横的方向为dp[0][j],从左向右遍历

纵的方向为dp[i][0],从上向下遍历

for(int i=0;i<m;i++)  dp[i][0]=1

for  (int j=0;j<n;j++)   dp[0][j]=1

只有向左或者向右两种可能,所以[i][0]只有一种方法,[0][j]只有一种方法

④遍历顺序

初始值在左边和上边,所以:

从左往右

从上往下

⑤打印dp数组
代码:
class solution
{
  public:
        int uniquePaths(int m,int 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]
        }
}

时间复杂度:O(m×n)

空间复杂度:O(m×n)

优化空间的一维数组代码:(这里会在下一篇里详细学习)
class solutin
{
  public:
         int uniquePaths(int m,int n)
         {
            vector<int>dp(n)
            for(int i=0;i<n;i++) dp[i]=1;
            for(int j=1;j<m;j++) 
            {
              for(int i=1;i<n;i++)
              {
                dp[i]+=dp[i-1];
              }
            }
          return dp[n-1] 
         }
}

时间复杂度:O(m×n)

空间复杂度:O(n)

第三种方法:图论

走到终点需要m+n-2步(横着走m,竖着走n,减去起点和终点),其中一定有m-1步向下走,则

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

要防止两个int相乘发生溢出,所以不能把算式的分子、分母都算出来再做除法,上面的代码不行

//计算分子时不断除以分母
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;
         }
}

计算分子的同时,不断除以分母

时间复杂度:O(n)

空间复杂度:O(1)

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值