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

二者含义没搞清楚,雅虎的笔试就这样的写错了。

求最长公共字串的题目写成了最长公共子序列。

子串要求字符必须是连续的,但是子序列就不是这样了。悲催了。

子序列跟子串的求法类似,都是使用动态规划的思想,s1每次增加一个字符,看与s2当前位置的字符是不是相同,如果相同做相应的处理,如果不同,做另外的处理。

子序列的处理方式:

相同的情况下,该二维数组的位置等于[i-1][j-1]+1

不同的情况下,该二维数组的位置等于MAX(d[i-1][j],d[i][j-1])

下面描述下子串的求法。

最长公共子串,要求字符是连续的。那么在[s1每次增加一个字符,看与s2当前位置的字符是不是相同]

相同的情况下,二维数组的位置等于[i-1][j-1]+1,

不同的情况下,二维数组的位置等于0,最后再查看二维数组的信息即可得到最长公共子串的长度,同时可以回溯二维数组得到最长公共字串的内容。

package InnerClass;

public class TT {
	public static void main(String ss[]) {
		get("abcdefg", "hbcsefgk");
	}

	private static void get(String s1, String s2) {

		int lcslen = 0;
		int pos_x = -1, pos_y = -1;
		// 初始化二维数组
		int flag[][] = new int[s1.length() + 1][s2.length() + 1];
		for (int i = 0; i < s1.length() + 1; i++) {
			flag[i][0] = 0;
		}
		for (int i = 0; i < s2.length() + 1; i++) {
			flag[0][i] = 0;
		}

		for (int i = 1; i <= s1.length(); i++) {
			for (int j = 1; j <= s2.length(); j++) {
				if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
					flag[i][j] = flag[i - 1][j - 1] + 1;
					if (flag[i][j] > lcslen) {
						lcslen = flag[i][j];
						pos_x = i;// 记录下最大长度在二维数组中的位置
						pos_y = j;
					}
				} else {
					flag[i][j] = 0;
				}
			}
		}
		// 方便观察,输出二维矩阵
		for (int i = 0; i < s1.length() + 1; i++) {
			for (int j = 0; j < s2.length() + 1; j++) {
				System.out.print(flag[i][j]);
			}
			System.out.println();
		}
		// 输出最长子串
		StringBuilder sb = new StringBuilder();
		while (flag[pos_x][pos_y] != 0) {
			sb.append(s1.charAt(pos_x - 1));
			pos_x--;
			pos_y--;
		}
		System.out.println(sb.toString());
	}
}


程序最后输出的是最长公共子串的逆序,把字符串倒转过来就是所求的了。代码还是比较简便的。

如果只是想求出最长公共子串的长度而不求子串是什么,可以把二维数组压缩到只需要两行的二维数组。最长公共子序列的回溯过程与最长公共子串的不同。子串只需要简单的回溯到flag[][]数组不是1的时候就可以了。子序列的回溯,在flag[][]数组中需要有三个方向,一个是向上(flag[i-1][j]),一个是向左(flag[i][j-1]),还有一个是向左上角(flag[i-1][j-1]),回溯直到flag[][]是0为止。

-----------------------------------分担个--------------------------------------

最长公共子串的求法,还有一种就是用后缀数组。

假设两个字符串为a和b,用一个在两个字符串中都没有出现的字符作为分隔形成一个字符串c=a#b,那么求c的后缀数组,先求后缀数组,再求出height数组【求height数组的时候,相邻的两个后缀只有一个包含#,另外一个不包含#,才求他们的height数组的值。(这是因为,如果两个都包含#,那么求出来的最长公共前缀就包含了a中的字符)】。height数组求出之后,其中的最大值就是ab两个字符串的最长公共字串的长度了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值