最长公共子序列(Longest Common Subsequence,LCS)问题是一个经典的计算机科学问题,它要求找出两个序列中最长的公共子序列。这里的“子序列”是指在原始序列中元素保持相对顺序的序列,但不必连续。
LCS问题的解决方法:
-
动态规划:LCS问题通常通过动态规划来解决,它使用一个二维数组来存储子问题的解。
-
递归:也可以通过递归的方式来解决LCS问题,但这种方法效率较低,因为它会重复计算很多子问题。
-
记忆化:记忆化是一种优化递归搜索的方法,它通过存储已经计算过的子问题的解来避免重复计算。
动态规划解决LCS问题的Java实现:
public class LongestCommonSubsequence {
public int lcs(String s1, String s2) {
int m = s1.length();
int n = s2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
LongestCommonSubsequence lcs = new LongestCommonSubsequence();
String s1 = "ABCBDAB";
String s2 = "BDCABA";
int result = lcs.lcs(s1, s2);
System.out.println("Length of LCS: " + result);
}
}
面试大厂题示例:
-
LCS问题:
描述:给定两个字符串,找到它们的最长公共子序列的长度。 -
LCS的变种:
描述:给定三个字符串,找到它们的最长公共子序列的长度。 -
LCS与回文:
描述:如果一个字符串是另一个字符串的子序列,那么它是否一定是后者的子串? -
LCS与编辑距离:
描述:给定两个字符串,找到它们之间的编辑距离。编辑距离定义为将一个字符串转换为另一个字符串所需的最少单字符编辑(插入、删除或替换)次数。
源码实现 - LCS与编辑距离:
public class EditDistance {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 1; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(
Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1),
dp[i - 1][j - 1] + 2
);
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
EditDistance editDistance = new EditDistance();
String word1 = "kitten";
String word2 = "sitting";
int result = editDistance.minDistance(word1, word2);
System.out.println("Edit distance: " + result);
}
}
在面试中,LCS问题可以考察应聘者对动态规划和递归思想的理解。通过实现LCS问题,可以展示你对算法设计和优化的掌握程度。希望这些示例能够帮助你更好地准备面试!最长公共子序列(LCS)问题是面试中常见的算法题目,它考察了候选人对动态规划的理解和应用能力。以下是三道与LCS相关的面试题目,以及相应的Java源码实现。
题目 1:求两个字符串的最长公共子序列
描述:
给定两个字符串,求它们的最长公共子序列。
示例:
输入: str1 = "ABCBDAB", str2 = "BDCABA"
输出: "BCAB"(答案不唯一)
Java 源码:
public class LongestCommonSubsequence {
public String lcs(String s1, String s2) {
int m = s1.length(), n = s2.length();
int[][] dp = new int[m + 1][n + 1];
int maxLength = 0, endIndex = -1;
// 构建动态规划表
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] > maxLength) {
maxLength = dp[i][j];
endIndex = i - 1;
}
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// 根据动态规划表回溯LCS
char[] lcs = new char[maxLength];
int i = endIndex, j = n;
while (i >= 0 && j >= 0 && maxLength > 0) {
if (s1.charAt(i) == s2.charAt(j)) {
lcs[--maxLength] = s1.charAt(i);
i--; j--; // 移动到对应的字符
} else if (dp[i - 1][j] > dp[i][j - 1]) {
i--; // 移动到s1的下一个字符
} else {
j--; // 移动到s2的下一个字符
}
}
return new String(lcs);
}
public static void main(String[] args) {
LongestCommonSubsequence lcs = new LongestCommonSubsequence();
String s1 = "ABCBDAB";
String s2 = "BDCABA";
String result = lcs.lcs(s1, s2);
System.out.println("LCS: " + result);
}
}
题目 2:求多个字符串的最长公共子序列
描述:
给定多个字符串,求它们的最长公共子序列。
示例:
输入: strs = ["ABCBDAB", "BDCABA", "BCD"]
输出: "BC"(答案不唯一)
Java 源码:
public class LongestCommonSubsequenceMultiple {
// 可以使用题目1中的lcs方法进行扩展,对多个字符串求LCS
// 此处省略实现,思路是对每一对字符串求LCS,然后使用得到的LCS作为新的字符串序列继续求LCS
}
题目 3:求字符串的最长回文子序列
描述:
给定一个字符串,求它的最长回文子序列。
示例:
输入: s = "BBABCBCAB"
输出: "BABCBAB"(答案不唯一)
Java 源码:
public class LongestPalindromicSubsequence {
public String longestPalindromicSubsequence(String s) {
// 将问题转化为求逆序字符串的LCS问题
String reversed = new StringBuilder(s).reverse().toString();
LongestCommonSubsequence lcs = new LongestCommonSubsequence();
return lcs.lcs(s, reversed);
}
public static void main(String[] args) {
LongestPalindromicSubsequence lps = new LongestPalindromicSubsequence();
String s = "BBABCBCAB";
String result = lps.longestPalindromicSubsequence(s);
System.out.println("Longest Palindromic Subsequence: " + result);
}
}
这些题目和源码展示了LCS问题及其变体在解决实际问题中的应用。在面试中,能够根据问题的特点选择合适的算法并实现其解决方案是非常重要的。希望这些示例能够帮助你更好地准备面试!