Fedora 计划默认启用磁盘加密

1、最长回文子序列

最长回文子序列(Longest Palindromic Subsequence,简称LPS)是常见的字符串问题之一,它指的是一个字符串中最长的回文子序列。回文指的是正反顺序读都相等的字符串。回文子序列不要求子序列在原字符串中是连续的。

比如,例如字符序列"BBABCBCAB",最长回文子序列是“BACBCAB”(可能不唯一),它的长度是7

2、如何去写其状态转移方程?

LPS问题可以通过动态规划来解决。我们定义状态dp[i][j]表示从字符串第i个字符到第j个字符的最长回文子序列的长度。对于一个长度为n的字符串,最长回文子序列的长度即为dp[0][n-1]。

2.1 初始化

对于长度为1的子串,我们已经初始化了dp[i][i]=1。

对于长度为2的子串,如果两个字符相等,则dp[i][i+1]=2,否则dp[i][i+1]=1。

2.2 状态转移方程

接下来,考虑如何推导状态转移方程。根据回文的定义,如果字符串中起始和结束字符相等,那么这两个字符一定是回文子序列的一部分。因此,我们可以得到以下转移方程:

dp[i][j] = dp[i+1][j-1] + 2 (i ≤ j, s[i] = s[j])

dp[i][j] = max(dp[i+1][j], dp[i][j-1]) (i ≤ j, s[i] ≠ s[j])

上述状态转移方程是基于以下两种情况考虑的:

  • 如果字符串的第一个和最后一个字符相等,那么它们一定在最长回文子序列中。

  • 如果字符串的第一个和最后一个字符不相等,那么它们两个不可能同时出现在最长回文子序列中。我们需要考虑“缩小问题规模”,去寻找子问题的最优解。

2.3 最终结果

我们可以从长度为1的子串和长度为2的子串开始,逐渐增加子串的长度求解dp[i][j],直到求得dp[0][n-1]为止。最终的结果即为最长回文子序列的长度。

3、代码如下:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1005;

int dp[N][N];

int main() {
    string s;
    cin >> s;
    int n = s.length();

    // 初始化
    for (int i = 0; i < n; i++) {
        dp[i][i] = 1;  // 单个字符是回文子序列
    }

    // 枚举子串长度
    for (int len = 2; len <= n; len++) {
        for (int i = 0; i < n - len + 1; i++) {
            int j = i + len - 1;
            if (s[i] == s[j]) {
                // 情况1
                dp[i][j] = dp[i+1][j-1] + 2;
            } else {
                // 情况2
                dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
            }
        }
    }

    cout << dp[0][n-1] << endl;
    return 0;
}

上述代码中,对于长度为1的子串,我们已经初始化了dp[i][i]=1。对于长度为2的子串,如果两个字符相等,则dp[i][i+1]=2,否则dp[i][i+1]=1。最后,我们逐渐增加子串长度,直到求出dp[0][n-1]的值。

最长回文子序列问题的时间复杂度为O(n^2),空间复杂度也为O(n^2)。

猜你喜欢

转载自www.oschina.net/news/235466/fedora-encryption-plans