【刷题(7)】多维动态规划

一、多维动态规划问题基础

  • 一般流程
    (1)首先,需要定义一个多维dp数组,明确每个下标含义
    (2)其次,需要确定状态转移方程,如,dp[i,j]=dp[i-1,j]+dp[j,j-1]
    (3)还有,需要初始化状态
    (4)注意,状态转移时,注意边界条件,下标要从1开始算起
  • m = string.length() n=vector.size()

二、62. 不同路径

1 题目

在这里插入图片描述

2 解题思路

(1)状态转移方程:想要走到(i,j),只能从(i-1,j),(i,j-1)走过来。因此,我们可以写出动态规划方程:dp[i,j]=dp[i-1,j]+dp[j,j-1]
(2)初始化状态:如果i=0,相当于只有一行的路径,所以dp[0][j]=1;如果j=0 相当于只有一列的路径,所以dp[i][0]=1

3 code

class Solution {
public:
    int uniquePaths(int m, int n) 
    {
        // 定义二dp维数组
        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;
        }

        // 状态转移
        // i,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];

    }
};

三、64. 最小路径和

1 题目

在这里插入图片描述

2 解题思路

(1)状态转移方程:dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j]
(2)初始化状态:如果i=0,相当于只有一行的路径,所以dp[0][j]=dp[0][j-1]+grid[0][j];如果j=0 相当于只有一列的路径,所以dp[i][0]=dp[i-1][0]+grid[i][0];dp[0][0]=grid[0][0]

3 code

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        // 定义一个dp二维数组
        int m =grid.size();
        int n = grid[0].size();
        vector<vector<int>> dp(m,vector<int>(n,0));

        // 初始化状态
        dp[0][0]=grid[0][0];
        for(int i=1;i<m;i++) dp[i][0]=dp[i-1][0]+grid[i][0];
        for(int j=1;j<n;j++) dp[0][j]=dp[0][j-1]+grid[0][j];

        // 状态转移
        for(int i=1;i<m;i++)
        {
            for(int j=1;j<n;j++)
            {
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+grid[i][j];
            }
        }

        return dp[m-1][n-1];

    }
};

四、5. 最长回文子串

1 题目

在这里插入图片描述

2 解题思路

(1)如果两个端点字符相等s[i]=s[j],就检查各自的下一位是否相等s[i+1]=s[j-1]?
(2)状态转移:1.两个端点要相等是s[i]=s[j],其次,s[j+1:i-1]也要为回文串
(3)初始化状态:如果j=i,子串长度为1,肯定是回文串;当j=i+1,子串长度位2,只要首尾两个端点相等,就是回文串

3 code

class Solution {
public:
    string longestPalindrome(string s) {
        // 定义一个dp二维数组
        int n = s.size();
        int length = 1; //最长回文子串的长度
        int start = 0; //最长回文子串的起点
        // dp[i][j]表示子串s[i:j]是否位回文子串
        vector<vector<bool>> dp(n,vector<bool>(n));

        for(int i=0;i<n;i++)
        {
            for(int j=i;j>=0;j--)
            { // 以i位起点,往回枚举起点j
                if(i==j)
                {// 情况一:i,j相等,子串长度为1
                    dp[j][i]=true;
                }
                else if(i==j+1)
                {// 情况一:j=i-1,子串长度为2
                    dp[j][i]= (s[i]==s[j]);
                }
                else
                {// 情况三:一般情况,子串长度大于等于3
                    if(s[i]==s[j])
                    {
                        dp[j][i]=dp[j+1][i-1];
                    }
                    else
                    {
                        dp[j][i]=false;
                    }
                }

                // 更新最长回文子串
                if(dp[j][i] && i-j+1 > length)
                {
                    length=i-j+1;
                    start=j;
                }
            }
        }
        
        return s.substr(start,length);
    }
};

五、1143. 最长公共子序列

1 题目

在这里插入图片描述

2 解题思路

(1)状态定义:定义dp[i][j]表示text1的前i个字符和text2的前j个字符之间最长公共子序列的长度
(2)状态转移:dp[i][j]的状态只能由dp[i-1][j-1],dp[i][k-1],dp[i-1][j]转移而来。

  • 当text1[i]==text2[j]
    dp[i][j]状态由dp[i-1][j-1]转移而来,dp[i][j]=dp[i-1][j-1]+1

  • 当text[i]!=text2[j]
    dp[i][j]状态由dp[i-1][j]和dp[i][j-1]状态中较大的而来,dp[i][j]=max(dp[i-1][j],dp[i][j-1])

3 code

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) 
    {
        int n = text1.size(), m = text2.size();
        vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
        for (int i = 0; i < n; i++) 
        {
            for (int j = 0; j < m; j++) 
            {
                if (text1[i] == text2[j]) 
                {
                    dp[i+1][j+1] = dp[i][j] + 1;
                } 
                else 
                {
                    dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]);
                }
            }
        }
        return dp[n][m];
    }
};

六、72. 编辑距离

1 题目

在这里插入图片描述

2 解题思路

(1)定义一个dp二维数组:dp[i][j]代表word1到i位置转换成word2到j位置需要最少步数
(2)状态转移: 当word1[i]==word2[j],dp[i][j]=dp[i-1][j-1]+1 当word1[i] != word2[j],dp[i][j]=min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+1,其中,dp[i-1][j-1]表示替换操作,dp[i-1][j]表示删除操作,dp[i][j-1]表示插入操作
(3)状态初始化,i=0时,怎么处理,i=j时,怎么处理

3 code

class Solution {
public:
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1,0));

        // 状态初始化
        for(int i=0;i<dp.size();i++){
            dp[i][0]=i;
        }
        for(int j=0;j<dp[0].size();j++){
            dp[0][j]=j;
        }

        // 状态转移,i,j从1开始便利
        for(int i=1;i<dp.size();i++){
            for(int j=1;j<dp[i].size();j++){
                if(word1[i-1]==word2[j-1]){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=min(dp[i-1][j-1],min(dp[i][j-1],dp[i-1][j]))+1;
                }
            }
        }
        return dp[word1.size()][word2.size()];
    }
};
  • 12
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m0_51579041

你的奖励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值