Java 查找给定两个字符串的所有公共子字符串
我遇到了一个问题语句,用于查找给定两个子字符串之间的所有公共子字符串,这样在任何情况下都必须打印最长的子字符串。问题陈述如下: 编写一个程序来查找两个给定字符串之间的公共子字符串。但是,不要包括包含在较长公共子字符串中的子字符串 例如,给定输入字符串Java 查找给定两个字符串的所有公共子字符串,java,string,algorithm,suffix-tree,dynamic-programming,Java,String,Algorithm,Suffix Tree,Dynamic Programming,我遇到了一个问题语句,用于查找给定两个子字符串之间的所有公共子字符串,这样在任何情况下都必须打印最长的子字符串。问题陈述如下: 编写一个程序来查找两个给定字符串之间的公共子字符串。但是,不要包括包含在较长公共子字符串中的子字符串 例如,给定输入字符串eatsleepnightxyz和eatsleepabcxyz,结果应为: eatsleep(由于eatsleepnightxyzeatsleepabcxyz) xyz(由于eatsleepnightxyzeatsleepabcxyz) a(由于e
eatsleepnightxyz
和eatsleepabcxyz
,结果应为:
(由于eatsleep
eatsleepnightxyz
)eatsleepabcxyz
(由于xyz
eatsleepnightxyz
)eatsleepabcxyz
(由于a
eatsleepnightxyz
)eatsleepabcxyz
(由于t
eatsleepnightxyz
)eatsleepabcxyz
e
eatsleepnightxyz
eatsleepabcxyz
,因为上述eatsleep
中已经包含了这两个e
。也不应包括eat
、eat
、ats
等,因为这些也都包含在eatsleep
中
在这种情况下,您不必使用字符串实用程序方法,如:contains、indexOf、StringTokenizer、split和replace
我的算法如下:我从蛮力开始,当我提高我的基本理解时,我将切换到更优化的解决方案
For String S1:
Find all the substrings of S1 of all the lengths
While doing so: Check if it is also a substring of
S2.
试图找出我的方法的时间复杂性
设两个给定字符串为n1字符串和n2字符串
其中Tn是所有子字符串的长度之和 Average是该总和除以生成的子字符串总数 这是一个简单的求和除法问题,其解如下O(n) 因此 我的算法的运行时间是O(n^5) 考虑到这一点,我编写了以下代码:
package pack.common.substrings;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class FindCommon2 {
public static final Set<String> commonSubstrings = new LinkedHashSet<String>();
public static void main(String[] args) {
printCommonSubstrings("neerajisgreat", "neerajisnotgreat");
System.out.println(commonSubstrings);
}
public static void printCommonSubstrings(String s1, String s2) {
for (int i = 0; i < s1.length();) {
List<String> list = new ArrayList<String>();
for (int j = i; j < s1.length(); j++) {
String subStr = s1.substring(i, j + 1);
if (isSubstring(subStr, s2)) {
list.add(subStr);
}
}
if (!list.isEmpty()) {
String s = list.get(list.size() - 1);
commonSubstrings.add(s);
i += s.length();
}
}
}
public static boolean isSubstring(String s1, String s2) {
boolean isSubstring = true;
int strLen = s2.length();
int strToCheckLen = s1.length();
if (strToCheckLen > strLen) {
isSubstring = false;
} else {
for (int i = 0; i <= (strLen - strToCheckLen); i++) {
int index = i;
int startingIndex = i;
for (int j = 0; j < strToCheckLen; j++) {
if (!(s1.charAt(j) == s2.charAt(index))) {
break;
} else {
index++;
}
}
if ((index - startingIndex) < strToCheckLen) {
isSubstring = false;
} else {
isSubstring = true;
break;
}
}
}
return isSubstring;
}
}
问题:鉴于投入
S1 = “neerajisgreat”;
S2 = “neerajisnotgreat”
S3 = “rajeatneerajisnotgreat”
对于S1和S2,输出应为:neerajis
和great
但对于S1和S3,输出应为:
neerajis
,raj
,great
,eat
,但我还是得到了neerajis
和great
作为输出。我需要弄清楚这件事
我应该如何设计代码?通常,这种类型的子字符串匹配是在称为(发音为try)的单独数据结构的帮助下完成的。最适合此问题的特定变体是。您的第一步应该是接受输入并构建后缀树。然后,您需要使用后缀树来确定最长的公共子字符串,这是一个很好的练习。对于任务,最好使用适当的算法,而不是暴力方法。维基百科描述了两种常见的解决方案:和 动态规划解需要O(nm)时间和O(nm)空间。这是Wikipedia伪代码最长公共子字符串的简单Java翻译:
public static Set<String> longestCommonSubstrings(String s, String t) {
int[][] table = new int[s.length()][t.length()];
int longest = 0;
Set<String> result = new HashSet<>();
for (int i = 0; i < s.length(); i++) {
for (int j = 0; j < t.length(); j++) {
if (s.charAt(i) != t.charAt(j)) {
continue;
}
table[i][j] = (i == 0 || j == 0) ? 1
: 1 + table[i - 1][j - 1];
if (table[i][j] > longest) {
longest = table[i][j];
result.clear();
}
if (table[i][j] == longest) {
result.add(s.substring(i - longest + 1, i + 1));
}
}
}
return result;
}
结果很明显:左上角是eatsleep
对角线条纹12345678
结果是右下角的xyz
对角线123
结果由顶部(第二行,第九列)附近的a
指示1
结果由左下角附近的t
指示1
6
和7
旁边的另一个1
呢?这些不算数,因为它们出现在由12345678
对角线形成的矩形内-换句话说,它们已经被eatsleep
覆盖
我建议只做一次,什么也不做,只是做桌子。然后,进行第二次循环,从右下角向后迭代,以收集结果集。让我们来看看。
public static Set<String> longestCommonSubstrings(String s, String t) {
int[][] table = new int[s.length()][t.length()];
int longest = 0;
Set<String> result = new HashSet<>();
for (int i = 0; i < s.length(); i++) {
for (int j = 0; j < t.length(); j++) {
if (s.charAt(i) != t.charAt(j)) {
continue;
}
table[i][j] = (i == 0 || j == 0) ? 1
: 1 + table[i - 1][j - 1];
if (table[i][j] > longest) {
longest = table[i][j];
result.clear();
}
if (table[i][j] == longest) {
result.add(s.substring(i - longest + 1, i + 1));
}
}
}
return result;
}
e a t s l e e p a b c x y z
e 1 0 0 0 0 1 1 0 0 0 0 0 0 0
a 0 2 0 0 0 0 0 0 1 0 0 0 0 0
t 0 0 3 0 0 0 0 0 0 0 0 0 0 0
s 0 0 0 4 0 0 0 0 0 0 0 0 0 0
l 0 0 0 0 5 0 0 0 0 0 0 0 0 0
e 1 0 0 0 0 6 1 0 0 0 0 0 0 0
e 1 0 0 0 0 1 7 0 0 0 0 0 0 0
p 0 0 0 0 0 0 0 8 0 0 0 0 0 0
n 0 0 0 0 0 0 0 0 0 0 0 0 0 0
i 0 0 0 0 0 0 0 0 0 0 0 0 0 0
g 0 0 0 0 0 0 0 0 0 0 0 0 0 0
h 0 0 0 0 0 0 0 0 0 0 0 0 0 0
t 0 0 1 0 0 0 0 0 0 0 0 0 0 0
x 0 0 0 0 0 0 0 0 0 0 0 1 0 0
y 0 0 0 0 0 0 0 0 0 0 0 0 2 0
z 0 0 0 0 0 0 0 0 0 0 0 0 0 3