dp就是写出状态转移方程就行了?我写不出来啊!|刷题打卡

578 阅读3分钟

一、题目描述:

二、思路分析:

这篇文章主要是将前文讲过的动态规划一般思路进行一个补充,因为有时候似乎状态转移方程格外难写,很多时候都明明知道这是动态规划,但就是写不出来状态转移方程。

本文着重讲下第二步:确定状态

我们讲确定状态进一步展开为状态表示和状态计算

状态表示

状态表示就是状态是什么,即dp[i][j]代表了满足条件i和满足条件j的最大/最小/的和

在这道题中,dp[i][j]就是指字符串1前i个长度,和字符串2前j个长度的子序列的最大长度

状态计算

状态计算就是一步步算出如何得到dp[i][j],你当然可以在草纸演算过程,大胆假设,最后删减成答案

如何得到这种表达如果让你困惑,可以改为从前面哪几个子问题得到或者答案由几种可能构成

在这道题中,我们想到dp[i][j],肯定和dp[i - 1][j]dp[i][j - 1]dp[i - 1][j - 1]有关,而对于str[i]和str[j] 也无非只有str[i] == str[j]str[i] != str[j]两种可能。

看起来两种可能的比较好分析,

  • str[i] == str[j]时,dp[i][j] = dp[i - 1][j - 1] + 1
  • str[i] != str[j]时,由于dp[i - 1][j - 1]同时也是dp[i - 1][j]所需要考虑的,因此不再将dp[i - 1][j - 1]纳入计算。当str[i] != str[j]时,最长的子序列只剩下包含str1[i]或者str2[j]两种可能(都不包含的可能 在刚才被排除了)
    • 我们大胆假设str1[i]为最长子序列的尾部,而str2[j]不是最长子序列的尾部,那就相当于str2[j]时没用的,此时dp[i][j] == dp[i][j - 1],因此我们可以用dp[i][j - 1]作为dp[i][j]的一种可能

那么此时状态转移方程就呼之欲出了:

dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if(str1[i] == str2[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);

三、AC 代码:

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m = text1.size();
        int n = text2.size();

        int dp[m + 1][n + 1];
        dp[0][0] =0, dp[0][1] =0, dp[1][0] = 0;
        for(int i = 0; i <= m; i ++){
            for(int j = 0; j <= n; j ++){
                if(i == 0 || j == 0){
                    dp[i][j] = 0;
                    continue;
                }
                dp[i][j] = 0;
                dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
                // printf("%d ", dp[i][j]);
                if(text1[i - 1] == text2[j - 1])dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
                // printf("%d \n ", dp[i][j]);
            }
        }
        return dp[m][n];
    }
};

四、总结:

这篇文章将确定状态更加细化,我个人觉得是对学动态规划有所帮助,但毕竟知见障,我也不知道是否真的有帮助,兄弟们可以在评论区交流下。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情