最长公共子序列和最长公共子串

最长公共子序列

题目描述

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

输入格式

第一行是一个数 n

接下来两行,每行为 n 个数,为自然数1,2,…,n 的一个排列。

输出格式

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

题目分析

第一阶段定义dp数组

(1)考虑规模。两个序列的长度就是规模,因为是两个,所以需要两个维度来表示。

(2)考虑限制。这里的限制就是对应位置相等,可以在递推的时候进行限制。

(3)写dp数组。 d p [ i ] [ j ] dp[i][j] dp[i][j]表示的第一个序列前i个值和第二个序列前j个值对应的最长公共子序列

第二阶段推导状态转移方程

(1)如果 s 1 [ i ] = = s 2 [ j ] , d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 s1[i]==s2[j],dp[i][j]=dp[i-1][j-1]+1 s1[i]==s2[j]dp[i][j]=dp[i1][j1]+1

(1)如果 s 1 [ i ] ! = s 2 [ j ] s1[i]!=s2[j] s1[i]!=s2[j],那么我们就要从前一个状态的最大值里面转移过来,前一个状态有哪些呢? d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] dp[i-1][j],dp[i][j-1] dp[i1][j],dp[i][j1]就是它的前一个状态, d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i1][j1]不是,因为他距离 d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i1][j1]已经变化了2步。 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) dp[i][j]=max(dp[i-1][j],dp[i][j-1]) dp[i][j]=max(dp[i1][j],dp[i][j1])

第三阶段写代码

(1)初始化。一开始长度是0。

(2)第一层for循环遍历规模,这里规模是两个维度表示的,所以也需要两层for循环。

(3)第二层for循环仍然遍历规模。

题目代码
import java.io.IOException;
import java.util.Scanner;

public class Main{
public static void main(String[] args) throws NumberFormatException, IOException {
	Scanner scanner = new Scanner(System.in);
	int n = scanner.nextInt();
	int m=n;
	int a[] = new int[n+1];
	int b[] = new int[m+1];
	int dp[][] = new int[n+1][m+1];
	for(int i = 1;i <= n;i++) 
		a[i] = scanner.nextInt();
	for(int i = 1;i <= m;i++) 
		b[i] = scanner.nextInt();
	for(int i = 1;i <= n;i++) {
		for(int j = 1;j <= m;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][m]);
}
}

在洛谷提交还是内存超限,离谱。

最长公共子串

题目分析

注意子串和子序列的差别,abcde中acd是一个子序列,但不是一个子串,abc是一个子串也是一个子序列。子串的要求要比子序列高。子串必须是连续的。那么这一点体现在哪里呢。体现在状态转移方程以及答案上。

第一阶段定义dp数组

(1)考虑规模。两个序列的长度就是规模,因为是两个,所以需要两个维度来表示。

(2)考虑限制。这里的限制就是对应位置相等,可以在递推的时候进行限制。

(3)写dp数组。 d p [ i ] [ j ] dp[i][j] dp[i][j]表示的第一个序列前i个值和第二个序列前j个值对应的最长公共子串

第二阶段推导状态转移方程

(1)如果 s 1 [ i ] = = s 2 [ j ] , d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 s1[i]==s2[j],dp[i][j]=dp[i-1][j-1]+1 s1[i]==s2[j]dp[i][j]=dp[i1][j1]+1

(1)如果 s 1 [ i ] ! = s 2 [ j ] , d p [ i ] [ j ] = 0 s1[i]!=s2[j],dp[i][j]=0 s1[i]!=s2[j]dp[i][j]=0

第三阶段写代码

(1)初始化。一开始长度是0。

(2)第一层for循环遍历规模,这里规模是两个维度表示的,所以也需要两层for循环。

(3)第二层for循环仍然遍历规模。

(4)答案。这里的 d p [ i ] [ j ] dp[i][j] dp[i][j]不一定是最终答案,答案要在过程中记录一个最大值。也就是所有dp值的最大值。 m a x ( d p [ i ] [ j ] ) max(dp[i][j]) max(dp[i][j])

题目代码
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Main{
public static void main(String[] args) throws NumberFormatException, IOException {
	Scanner scanner = new Scanner(System.in);
	char a[];
	char b[];
	a = (" "+scanner.next()).toCharArray();
	b = (" "+scanner.next()).toCharArray();
	int n = a.length-1;
	int m = b.length-1;
	int dp[][] = new int[n+1][m+1];	
	int ans = 0;
	for(int i = 1;i <= n;i++) {
		for(int j = 1;j <= m;j++) {
			if(('0'<=a[i]&&a[i]<='9') || ('0'<=b[j]&&b[j]<='9')) continue;
			if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;
			else dp[i][j] = 0;
			ans = Math.max(ans, dp[i][j]);
		}
	}
	System.out.println(ans);
}
}

你可能感兴趣的:(动态规划,算法)