SW练习_POJ1458_最长公共子序列_LCS

本文详细解析了最长公共子序列问题的经典动态规划解法,通过动态转移方程实现高效求解,同时提供了两种不同实现方式的代码示例,一种使用二维数组存储中间结果,另一种优化内存使用,仅保留上一行结果。

解题思路:本题裸的最长公共子序列问题 经典dp 
           动态转移方程 
                   1:char(a) == char(b) dp[i][j] = dp[i-1][j-1] +1;                   
                   2:char(a) != char(b) dp[i][j] = max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])
耗费了约7个小时,这个坑比较大(输入的中间的空格不固定,试了好几种方式的输入,都不行)

package info.frady.dp;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

/**
 * meng3.wei 2020.05.16
 */
public class POJ1458最长公共子序列 {

    public static void main(String[] args) throws Exception{
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String a = scanner.next();
            String b = scanner.next();
            //System.out.println(process(a,b));
            System.out.println(process2(a,b));
        }
    }

    public static int process2 (String a,String b){
        int[] up=new int[a.length()+1];
        int[] current=new int[a.length()+1];
        for (int i = 1; i <=b.length() ; i++) {//取出一个b和a的每个字母进行比较
            up=current;
            current=new int[a.length()+1];
            for (int j = 1; j <=a.length() ; j++) {//取出a的每一个字母
                if(b.charAt(i-1)==a.charAt(j-1)){//相等,取左上方+1
                    current[j]=up[j-1]+1;
                }else{//两个不相等,取左边或者上面最大的一个
                    current[j]=max(max(current[j-1],up[j]),up[j-1]);
                }

            }
            //System.out.println(Arrays.toString(current));
        }
        return current[current.length-1];
    }
    public static int process (String a,String b){
        int[][] dp=new int[a.length()+1][b.length()+1];
        for (int i = 1; i <=a.length() ; i++) {
            for (int j = 1; j <=b.length() ; j++) {
                if(a.charAt(i-1)==b.charAt(j-1)){//相等,取左上方+1
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{//两个不相等,取左边或者上面最大的一个
                    dp[i][j]=max(max(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1]);
                }

            }
            //System.out.println(Arrays.toString(current));
        }
        return dp[a.length()][b.length()];//[a.length()];
    }

    public static int max(int i,int j){
        if(i>j){
            return i;
        }else{
            return j;
        }
    }
}

参照:https://blog.youkuaiyun.com/lijinyuliangyan/article/details/78502933

 

下面是落谷P1439求最长子序列的

https://www.luogu.com.cn/problem/P1439

用这个方法无法AC,但是这个代码比上面的优化了一些

上面的要开N*N的数组,这个常常内存就限制了

实际我们根据不需要记录每一行的结果,只需要记录上一行的结果就可以

package info.frady.luogu;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

//最长公共子序列
//转换方程
// 如果不相等,取左侧和上方中最大的一个 f(m,n)=max(f(m-1,n),f(m,n-1))
// 如果相等,取 上、左、左上+1 中最大的一个 f(m,n)=max(f(m-1,n),f(m,n-1),f(m-1.n-1)+1)
// 此处要注意!!!!每行为 nn 个数,为自然数 1,2,\ldots,n1,2,…,n 的一个排列。
public class P1439 {

    public static void main(String[] args) throws Exception{
            BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st=new StringTokenizer(reader.readLine());
            int N=Integer.parseInt(st.nextToken());//要对比的字串的长度
           /*String[] stra=reader.readLine().split(" ");
           String[] strb=reader.readLine().split(" ");*/
           int[] stra=new int[N];
        int[] strb=new int[N];
            st=new StringTokenizer(reader.readLine());
        for (int i = 0; i <N ; i++) {
            stra[i]=Integer.parseInt(st.nextToken());
        }
        st=new StringTokenizer(reader.readLine());
        for (int i = 0; i <N ; i++) {
            strb[i]=Integer.parseInt(st.nextToken());
        }

           int[] pres=new int[N+1];//存储上一行的结果
           int[] res=new int[N+1];//存储当前行的结果 b的当前行 与 a的每一列的对比结果
        for (int i = 1; i <=N ; i++) {// b的第i个字母
            for (int j = 1; j <=N ; j++) { // 依次和a的第j字母对比
                if(strb[i-1] == (stra[j-1])){// 如果相等,取 上、左、左上+1 中最大的一个 f(m,n)=max(f(m-1,n),f(m,n-1),f(m-1.n-1)+1)
                    res[j]= max( max( res[j-1],pres[j] ),pres[j-1]+1 );
                    //System.out.println(Arrays.toString(res));
                }else {// 如果不相等,取左侧和上方中最大的一个 f(m,n)=max(f(m-1,n),f(m,n-1))
                    res[j] = max( res[j-1] ,pres[j] );

                }
            }
            System.arraycopy(res,0,pres,0,res.length);

        }
        System.out.println(res[res.length-1]);
            reader.close();
        }

        public static int max(int a,int b){
            return a>=b? a:b;
        }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值