最长公共子序列(可打印所有子序列)

本文展示了如何使用Java编程实现求解两个字符串的最长公共子序列(LCS),并输出所有可能的LCS。通过动态规划方法计算LCS的长度,并借助HashSet进行结果去重,确保打印出所有不重复的LCS。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import java.util.HashSet;
public class MyLCS {


	public static int dp[][] = null;
	public static String str1 = null;
	public static String str2 = null;
	//用于存放结果
	public static char[] result = null;
	//用于结果去重
	public static HashSet<String> set = new HashSet<String>();
	public static void printLCS(int x, int y, int cur){
		if(x >= str1.length() || y >= str2.length()){
			String str = new String(result);
			if(set.contains(str)) return;
			set.add(str);
			System.out.println(str);
			return;
		}
		if(str1.charAt(x) == str2.charAt(y)){
			result[cur] = str1.charAt(x);
			printLCS(x+1,y+1,cur+1);
		}else if(dp[x+1][y] > dp[x][y+1]){
			printLCS(x+1,y,cur);
		}else if(dp[x+1][y] < dp[x][y+1]){
			printLCS(x,y+1,cur);
		}else{
			printLCS(x+1,y,cur);
			printLCS(x,y+1,cur);
		}
	}
	public static void getLCS(){
		for(int i=str1.length()-1; i>=0; i--){
			for(int j=str2.length()-1; j>=0; j--){
				if(str1.charAt(i) == str2.charAt(j)){
					dp[i][j] = dp[i+1][j+1] + 1;
				}else{
					dp[i][j] =Math.max(dp[i+1][j], dp[i][j+1]);
				}
			}
		}
		result = new char[dp[0][0]];
		System.out.println(dp);
		printLCS(0,0,0);
	}
 	public static void main(String[] args) {
 		str1 = "cegefkh";
		str2 = "acgbfhk";
		dp = new int[str1.length() + 1][str2.length()+1];
		getLCS();
	}
}

### 找出所有最长公共子序列(LCS)的方法 为了找到两个字符串的所有可能的最长公共子序列(LCS),可以基于动态规划的思想扩展标准的LCS算法。以下是具体实现方式: #### 动态规划表构建 首先,创建一个二维数组 `dp` 来存储两个字符串之间前缀的最大匹配长度。对于给定的两个字符串 X 和 Y,其长度分别为 m 和 n,则定义 dp[i][j] 表示 X 的前 i 个字符和 Y 的前 j 个字符之间的最大匹配长度。 如果 X[i-1]==Y[j-1] 则有关系式: \[ \text{dp}[i][j] = \text{dp}[i-1][j-1] + 1 \] 否则, \[ \text{dp}[i][j] = \max(\text{dp}[i-1][j], \text{dp}[i][j-1]) \] 此部分与常规 LCS 算法相同[^1]。 #### 回溯获取所有 LCS 序列 当完成上述表格填充后,可以从右下角回溯到左上角来收集所有的 LCS 序列。由于可能存在多条路径达到相同的最大值,因此需要记录每一步的选择情况并递归探索这些可能性。 下面是一个 Python 版本的例子展示如何实现这一过程: ```python def all_lcs(x, y): m, n = len(x), len(y) # 创建 DP table dp = [[0]*(n+1) for _ in range(m+1)] # 填充 DP table for i in range(1, m+1): for j in range(1, n+1): if x[i-1] == y[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) result_set = set() def backtrack(i, j, lcs_str=""): nonlocal result_set if i == 0 or j == 0: result_set.add(lcs_str[::-1]) return elif x[i-1] == y[j-1]: backtrack(i-1, j-1, x[i-1]+lcs_str) elif dp[i-1][j] >= dp[i][j-1]: backtrack(i-1, j, lcs_str) if dp[i][j-1] >= dp[i-1][j]: backtrack(i, j-1, lcs_str) backtrack(m, n) return list(result_set) if __name__ == "__main__": str1 = "ABCBDAB" str2 = "BDCABA" res = all_lcs(str1, str2) print(res) ``` 该程序会打印出 `"ABCBDAB"` 和 `"BDCABA"` 这两串字元间的所有最长公共子序列[^4]。 ### 注意事项 需要注意的是,在某些情况下可能会有大量的重复计算,这可能导致效率低下。为此可考虑引入记忆化技术或其他优化手段减少不必要的运算次数[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值