动态规划(DP)经典简单入门题目集

一、三步问题

题目链接
在这里插入图片描述

  • 我们可以列出一个数组dp[n],在这个数组中的第i位保存的数据就是上i个楼梯有多少种走法,由此我们可以先得到:
    dp[1]=1;
    dp[2]=2;
    dp[3]=4;
  • 同时我们可以推出状态转移访方程为:dp[i]=(dp[i-1]+dp[i-2]+dp[i-3])
    代码如下:
class Solution {
    
    
public:
    int waysToStep(int n) {
    
    
            long long dp[1000000]={
    
    0};
            dp[1]=1;
            dp[2]=2;
            dp[3]=4;
                for(int i=4;i<=n;i++)
                {
    
    
                    dp[i]=(dp[i-1]+dp[i-2]+dp[i-3])%1000000007;
                 }
            return dp[n];
    }
};

二、连续数列

题目链接
在这里插入图片描述

  • 我们同样可以列出一个数组dp[n],在这个数组中的第i位保存的数据就是第i位能得到的最大连续和,但是和上题不同的是,这里的dp[n]并不是题目要求的最大连续和,只是第n位能取得的最大和,所以真正的答案可能存在1~n之间,这里我们还要用一个变量来记录最大和
  • 同样,我们令dp[0]=nums[0],因为这一位的最大和只能是它自己,之后的每一位,要么加上前一位的最大和,要么就不加,然后可推出状态转移方程为:
    dp[i]=max(nums[i],dp[i-1]+nums[i]);
    代码如下:
class Solution {
    
    
public:
    int maxSubArray(vector<int>& nums) {
    
    
        int dp[100000]={
    
    0};
        int ans=nums[0];
        dp[0]=nums[0];
        for(int i=1;i<nums.size();i++)
        {
    
    
            dp[i]=max(nums[i],dp[i-1]+nums[i]);
            ans=max(dp[i],ans);
        }
        return ans;
    }
};

三、打家劫舍

题目链接

在这里插入图片描述在这里插入图片描述

  • 我们同样列出一个数组dp[n],在这个数组中的第i位保存的数据就是第i位能偷到的最大金额,这题的特点是不能连续的偷窃,所以我们的状态转移方程也要进行相应的变换。
  • 对于每一个i来说,只有偷和不偷两种选择,如果选择不偷,那么第i位的偷取的最大金额数就会和i-1位的金额数一致,如果选择偷的话,那么第i位的金额就应该是第i-2位的金额数加上第i位可偷取的金额数之和,具体方程如下:
    dp[i]=max(dp[i-1],dp[i-2]+nums[i]);

代码为:

class Solution {
    
    
public:
    int rob(vector<int>& nums) {
    
    
        if(nums.size()==0)
        return 0;
        if(nums.size()==1)
        return nums[0];
        int dp[100000]={
    
    0};
        dp[0]=nums[0];
        dp[1]=max(nums[1],dp[0]);
        for(int i=2;i<nums.size();i++)
        {
    
    
            dp[i]=max(dp[i-1],dp[i-2]+nums[i]);
        }
        return dp[nums.size()-1];
    }
};

四、不同路径

题目链接

在这里插入图片描述在这里插入图片描述

  • 这题与上面的题目不同的是,这题需要我们建立一个二维的dp数组dp[m][n],相对应的每个dp[i][j]就代表着走到坐标i,j有多少条走法。
  • 而我们还需要对这个数组进行一下初始化,由于只能向下或者只能向上,所以我们可以假定一直向左和一直向下,将二维数组的第一列和第一行全部赋值为1,之后我们也可以得到状态转移方程如下:
    dp[i][j]=dp[i-1][j]+dp[i][j-1];
    代码为:
class Solution {
    
    
public:
    int uniquePaths(int m, int n) {
    
    
        int dp[m][n];
        if(m==0||n==0)
        return 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-1][j]+dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
};

五、最小路径和

题目链接

在这里插入图片描述

  • 这题和上题很类似,转移方程也十分的相似,因为只能向右或者向下走,所以我们只要考虑向下和向右走哪个能符合题目条件即可,我们可以将上题的转移方程变式一下,就可以得到:
    dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];

代码为:

class Solution {
    
    
public:
    int minPathSum(vector<vector<int>>& grid) {
    
    
        int dp[grid.size()][grid[0].size()];
        dp[0][0]=grid[0][0];
        for(int i=1;i<grid.size();i++)
        dp[i][0]=dp[i-1][0]+grid[i][0];
        for(int i=1;i<grid[0].size();i++)
        dp[0][i]=dp[0][i-1]+grid[0][i];
        for(int i=1;i<grid.size();i++)
        {
    
    
            for(int j=1;j<grid[0].size();j++)
            {
    
    
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }
        return dp[grid.size()-1][grid[0].size()-1];
    }
};

猜你喜欢

转载自blog.csdn.net/qq_43663263/article/details/105849799