DP字符串类型题汇总

DP字符串类型题汇总

  1. 最长公共子串(LCS)
//输出A和B最长公共子串的长度, 并打印结果
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int d[maxn][maxn];
char a[maxn], b[maxn];
int la, lb;
int main() {
#ifdef LOCAL
    freopen("E:\\Cpp\\1.in", "r", stdin);
#endif
    scanf("%s%s", a, b);
    la = strlen(a);
    lb = strlen(b);
    memset(d, 0, sizeof(d));
    for (int i = 1; i <= la; i++)
        for (int j = 1; j <= lb; j++) {
            if (a[i - 1] == b[j - 1])
                d[i][j] = d[i - 1][j - 1] + 1;
            else
                d[i][j] = max(d[i - 1][j], d[i][j - 1]);
        }
    int len = d[la][lb];
    printf("%d\n", len);
    stack<char> ans;
    int i = la, j = lb;
    while (d[i][j]) {
        if (d[i][j] == d[i - 1][j])
            i--;
        else if (d[i][j] == d[i][j - 1])
            j--;
        else {
            ans.push(a[i - 1]);
            i--;
            j--;
        }
    }
    while (!ans.empty()) {
        printf("%c", ans.top());
        ans.pop();
    }
    return 0;
}
  1. 最短公共父串
//输出A和B最短公共父串的长度以及在该长度下可以生成的父串个数
#include <bits/stdc++.h>
using namespace std;
const int maxn = 15;
int d[maxn][maxn], f[maxn][maxn];
int len1, len2, cnt;
char a[maxn], b[maxn];
int main() {
#ifdef LOCAL
    freopen("E:\\Cpp\\1.in", "r", stdin);
#endif
    scanf("%s", a + 1);
    scanf("%s", b + 1);
    len1 = strlen(a + 1), len2 = strlen(b + 1);
    int m = max(len1, len2);
    for (int i = 0; i <= m; i++) {
        d[i][0] = d[0][i] = i;
        f[i][0] = f[0][i] = 1;
    }
    for (int i = 1; i <= len1; i++) {
        for (int j = 1; j <= len2; j++) {
            if (a[i] == b[j]) {
                d[i][j] = d[i - 1][j - 1] + 1;
                f[i][j] = f[i - 1][j - 1];
            } else {
                d[i][j] = min(d[i - 1][j], d[i][j - 1]) + 1;
                if (d[i - 1][j] < d[i][j - 1])
                    f[i][j] = f[i - 1][j];
                else if (d[i][j - 1] < d[i - 1][j])
                    f[i][j] = f[i][j - 1];
                else
                    f[i][j] = f[i - 1][j] + f[i][j - 1];
            }
        }
    }
    printf("%d %d", d[len1][len2], f[len1][len2]);
}
//打印A和B最短公共父串
#include <bits/stdc++.h>
using namespace std;
const int maxn = 15;

int d[maxn][maxn];
int flag[maxn][maxn];
char str[maxn], str1[maxn];
char P[maxn];
int k;
void print(int l, int r) {
    if (l == 0 && r == 0)
        return;
    if (flag[l][r] == 0) {
        print(l - 1, r - 1);
        printf("%c", str[l]);
    } else if (flag[l][r] == 1) {
        print(l - 1, r);
        printf("%c", str[l]);
    } else {
        print(l, r - 1);
        printf("%c", str1[r]);
    }
}

void LCS() {
    memset(flag, 0, sizeof(flag));
    int n = strlen(str + 1);
    int m = strlen(str1 + 1);
    for (int i = 1; i <= n; i++) ///初始化不能少
        flag[i][0] = 1;
    for (int i = 1; i <= m; i++)
        flag[0][i] = -1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (str[i] == str1[j]) {
                d[i][j] = d[i - 1][j - 1] + 1;
                flag[i][j] = 0;
            } else {
                if (d[i - 1][j] > d[i][j - 1]) {
                    d[i][j] = d[i - 1][j];
                    flag[i][j] = 1;
                } else {
                    d[i][j] = d[i][j - 1];
                    flag[i][j] = -1;
                }
            }
        }
    }
    print(n, m);
    printf("\n");
}
int main() {
    while (scanf("%s%s", str + 1, str1 + 1) != EOF) {
        LCS();
    }
    return 0;
}
  1. 插入字符生成回文串
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int n, m;
int d[maxn][maxn];
int dp(string s, string t) {
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            if (s[i - 1] == t[j - 1])
                d[i][j] = d[i - 1][j - 1] + 1;
            else
                d[i][j] = max(d[i - 1][j], d[i][j - 1]);
        }
    return d[n][m];
}
int main() {
#ifdef LOCAL
    freopen("E:\\Cpp\\1.in", "r", stdin);
#endif
    string s;
    cin >> s;
    string t(s.rbegin(), s.rend());
    n = s.size();
    m = n;
    cout << n - dp(s, t);

    return 0;
}
  1. 分割字符串生成回文子串
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1050;
int d[maxn];
int s[maxn][maxn];
string st;
int work() {
    int len = st.size();
    memset(s, 0, sizeof(s));
    for (int i = 0; i < len; i++) {
        int p, q;
        s[i][i] = 1;
        // ji
        p = i - 1;
        q = i + 1;
        while (p >= 0 && q < len && st[p] == st[q]) {
            s[p][q] = 1;
            p--;
            q++;
        }
        // odd_left
        p = i - 1;
        q = i;
        while (p >= 0 && q < len && st[p] == st[q]) {
            s[p][q] = 1;
            p--;
            q++;
        }
        // odd_right
        p = i;
        q = i + 1;
        while (p >= 0 && q < len && st[p] == st[q]) {
            s[p][q] = 1;
            p--;
            q++;
        }
    }
} // s[i][j]是否为回文串
int main() {
    int T;
    cin >> T;
    // string st;
    while (T--) {
        cin >> st;
        work();
        int len = st.size();
        for (int i = 0; i < len; i++)
            d[i] = 100000;
        for (int i = 0; i < len; i++) {
            int j = 0;
            if (s[0][i])
                d[i] = 1;
            else
                for (j = 0; j < i; j++) {
                    if (s[j + 1][i])
                        d[i] = min(d[i], d[j] + 1);
                }
        }
        cout << d[len - 1] << endl;
    }
    return 0;
}
  1. 删除最少字符使两串相同
int delet(string s, string t) {
    int n = s.size();
    int m = t.size();
    if (n == 0)
        return m;
    if (m == 0)
        return n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            if (s[i - 1] == t[j - 1])
                d[i][j] = d[i - 1][j - 1] + 1;
            else
                d[i][j] = max(d[i - 1][j], d[i][j - 1]);
        }
    return n + m - 2 * d[n][m];
}
  1. 修改或删除最少字符使两串相同
int edit(string s, string t) {
    int n = s.size();
    int m = t.size();
    if (n == 0)
        return m;
    if (m == 0)
        return n;
    for (int i = 0; i <= n; i++)
        d[i][0] = i;
    for (int j = 0; j <= m; j++)
        d[0][j] = j;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            if (s[i - 1] == t[j - 1])
                d[i][j] = d[i - 1][j - 1];
            else
                d[i][j] =
                    min(d[i - 1][j - 1], min(d[i - 1][j], d[i][j - 1])) + 1;
        }
    return d[n][m];
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值