最长公共子序列(动态规划法+优化)

最长公共子序列(LCS)(1)

题目描述

给出1-n的两个排列P1和P2,求它们的最长公共子序列。

输入

第一行是一个数n;(n是5~1000之间的整数)数据范围小,可以用二维数组dp
接下来两行,每行为n个数,为自然数1-n的一个排列(1-n的排列每行的数据都是1-n之间的数,但顺序可能不同,比如1-5的排列可以是:1 2 3 4 5,也可以是2 5 4 3 1)。

输出

一个整数,即最长公共子序列的长度。

样例输入 
5 
3 2 1 4 5
1 2 3 4 5
样例输出 
3
import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        int []a=new int[n+1];
        int []b=new int[n+1];
        int [][] dp=new int[n+1][n+1];
        for(int i=1;i<=n;i++){
            a[i]=scan.nextInt();
        }
        for(int i=1;i<=n;i++){
            b[i]=scan.nextInt();
        }
        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]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        System.out.println(dp[n][n]);
    }
}

 最长公共子序列(LCS)(2)

题目描述

给出1-n的两个排列P1和P2,求它们的最长公共子序列。
和最长公共子序列(LCS)(1)问题不同的是,本题的n在5-100000之间。数据范围大,要用映射的做法把问题转化为求最长递增子序列的长度

输入

第一行是一个数n;(n是5-100000之间的整数)
接下来两行,每行为n个数,为自然数1-n的一个排列(1-n的排列每行的数据都是1-n之间的数,但顺序可能不同,比如1-5的排列可以是:1 2 3 4 5,也可以是2 5 4 3 1)。

输出

一个整数,即最长公共子序列的长度。

样例输入 
5 
3 2 1 4 5
1 2 3 4 5
样例输出 
3
提示

对于50%的数据,n≤1000
对于100%的数据,n≤100000

import java.util.Scanner;
 
public class Main {
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        int[] p1=new int[n];
        int[] p2=new int[n];
        for(int i=0;i<n;i++){
            p1[i]=scan.nextInt();
        }
        for(int i=0;i<n;i++){
            p2[i]=scan.nextInt();
        }
        //映射
        int[] pos=new int[n+1];
        for(int i=0;i<n;i++){
            pos[p2[i]]=i;
        }
        int[] nums=new int[n+1]; //[2,1,0,3,4]
        for(int i=0;i<n;i++){
            nums[i]=pos[p1[i]];
        }
        //求nums的最长递增子序列
        int[] tails=new int[n];
        int len=0;
        for(int i=0;i<n;i++){
            int num=nums[i];
            int left=0;
            int right=len-1;
            int insertpos=len;
            while (left<=right){
                int mid=left+(right-left)/2;
                if(tails[mid]<num){
                    left=mid+1;
                }else{
                    insertpos=mid;
                    right=mid-1;
                }
            }
            tails[insertpos]=num;
            if(insertpos==len){
                len++;
            }
        }
        System.out.println(len);
 
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值