子序列问题学习指南

前置芝士

最长公共子序列

朴素算法

时间复杂度:\(O(n^2)\)

const int N=1001;
int a[N],b[N],dp[N][N];
int n;
int solve(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++){
        for(int 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;
}

优化算法

时间复杂度:\(O(nlogn)\)

离散化+最长递增子序列+二分查找

const int N=100007;
int a[N],b[N],f[N],t[N];
int n;
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++) {cin>>a[i];t[a[i]]=i;}
    for(int i=1;i<=n;i++) {cin>>b[i];f[i]=0x3f3f3f3f;}
    f[t[b[1]]]=1;
    int len=1;
    for(int i=2;i<=n;i++){
        if(t[b[i]]>f[len]) f[++len]=t[b[i]];
        else{
            int l=1,r=len,mid;
            while(l<r){
                mid=(l+r)/2;
                if(f[mid]>t[b[i]]) r=mid;
                else l=mid+1;
            }
            f[l]=min(f[l],t[b[i]]);
        }
    }
    cout<<len<<endl;
}

最长上升子序列

朴素算法

时间复杂度:\(O(n^2)\)

优化算法

时间复杂度:O(nlogn)

如果当前有两个长度为2的上升子序列[1,2]和[1,4],那么显而易见,前者要更优。因为前者的末位元素2要比后者的末位元素4更小。如果后续遍历到的新元素为3,则就可以加入前者,而不能加入后者。

所以,我们总是希望当前构造的上升子序列中的元素较小。

posted @ 2023-10-29 17:52  White_Sheep  阅读(8)  评论(0编辑  收藏  举报