最长公共子序列—LCS

定义:给定一个序列X=(X1, X2 , … , Xn),另一个序列Z=(Z1, Z2, … , Zk)满足如下条件时称为X的子序列,即存在一个严格递增的X的下表序列(i1, i2, … , ik),对所有的 j=1,2, … ,k ,满足 Xi(j) =Zj。例如,Z={B, C, D, B}是X={A, B, C , B, D, A, B}的子序列,对应的下标为(2,3,5,7)。给定两个序列X和Y,如果Z既是X的子序列,也是Y的子序列,我们称它是X和Y的公共子序列(common subsequence)。
最长公共子序列问题(longest-common-subsequence problem):给定两个序列X={X1, X2, … Xm}和Y={Y1, Y2, … Yn},求X和Y长度最长的公共子序列。

动态规划法( O(n^2) )

这里是引用
这里是引用

P1439 【模板】最长公共子序列

这道题中O(n^2)的复杂度过不了

//O(n^2)
#include <iostream>
#include<cmath>
using namespace std;

#define maxn 1001
int a[maxn],b[maxn],n;
int dp[maxn][maxn];
int main()
{
    
    
    cin>>n;
    int i,j;
    for(i=1;i<=n;i++)
    {
    
    
        cin>>a[i];
        dp[i][0]=0;
    }
    for(j=1;j<=n;j++)
    {
    
    
        cin>>b[j];
        dp[0][j]=0;
    }
    for(i=1;i<=n;i++)
    {
    
    
        for(j=1;j<=n;j++)
        {
    
    
            if(a[i]==b[j])
                dp[i][j]=dp[i-1][j-1]+1;
            else
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
        }
    }
    cout <<dp[n][n]<< endl;
    return 0;
}

考虑O(NlogN)的时间复杂度,转化为LIS问题:
以第一个串为基准,用第二个串来匹配第一个串,如样例:3 2 1 4 5 离散化表示为3-1;2-2;1-3;4-4;5-5;现在第二串1 2 3 4 5 按离散化的表示为:3 2 1 4 5。第一个串离散化后的数组是满足上升,第二串离散化后满足上升的序列也就是满足原串的排列顺序的,现在的问题就变成了求一个最长不下降序列。

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

const int maxn =100010, minn = 0x7f7f7f7f;
int low[maxn], a[maxn],b[maxn],c[maxn];
int n, ans;

int b_search(int *c, int R, int x)
//二分查找,返回c数组中第一个>=x的位置
{
    
    
    int L = 1, mid;
    while(L<R)
    {
    
    
        mid = (L+R) >> 1;
        if(c[mid] <= x)
            L = mid + 1;
        else
            R = mid;
    }
    return L;
}
int main()
{
    
    
    cin>>n;
    for(int i=1; i<=n; i++)
    {
    
    
        cin>>a[i];
        c[a[i]]=i;
        low[i] = minn;
    }
    for(int i=1;i<=n;i++)
        cin>>b[i];
    low[1] = c[b[1]];
    ans = 1;   //初始时LIS长度为1
    for(int i=2;i<=n;i++)
    {
    
    
        if(c[b[i]] > low[ans])  //若c[b[i]]>=low[ans],直接把c[b[i]]接到后面
            low[++ans] = c[b[i]];
        else   //否则,找到low中第一个>=c[b[i]]的位置low[j],用c[b[i]]更新low[j]
            low[b_search(low, ans, c[b[i]])] = c[b[i]];
    }
    cout<<ans;
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_50932477/article/details/119243572