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

被折叠的 条评论
为什么被折叠?



