本文旨在提供一种思路和现成的代码来解决提取两个字符串中最大相同子串的问题(可能不止一个),如"afasdghellosfdabcde"与“helloabcde”中最大相同子串分别为"hello"与"abcde"。
思路
与查找最大公因数的思想类似,先从两个字符串中找到长度及较短的字符串,记为minStr,较长字符串记为maxStr。
第一次先判断minStr是否本身为maxStr的子串,若是则minStr即为所求子串。若不是,则依次遍历长度为minStr.length() - i (i = 1,2,3…)的minStr的子串进行判断,直到找到或者遍历所有子串没有找到为止。
思路很简单,直接上代码。
程序
为方便理解起见,我们先假定最长子串有且仅有一个,即不会出现多个内容不同的子串同为最长子串。
public String getMaSubString(String str1, String str2) {
// 这地方有个细节,minStr部分不要用<=,若使用<=则两个字符串长度相等时minStr和maxStr时都为str1
String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
String minStr = (str1.length() < str2.length()) ? str1 : str2;
for (int i = 0; i < minStr.length(); i++) {
// x,y 用以记录子串的前后端位置,x由0开始,每次循环x与y++,直到y超出minStr.length(),确保所有子串都被遍历
// i = 0 时对应子串就为minStr本身,i = minStr.length()-1 时对应子串长度就为1
for (int x = 0, y = minStr.length() - i; y <= minStr.length(); x++, y++) {
String subStr = minStr.substring(x, y); // 获取子串,区间左闭右开
if (maxStr.contains(subStr)) { // 判断是否被包含
return subStr;
}
}
}
// 没找到返回null
return null;
}
读懂上面的程序,那么对于有多个最长子串的情形解决方法也不难理解了。我们采取容器的形式对结果进行储存,对上述程序稍作修改,结果如下:
public ArrayList<String> getMaxSameString(String str1, String str2) { // 返回类型修改为ArrayList
ArrayList<String> subStrs = new ArrayList<>(); // 用于储存结果的ArrayList
String maxStr = (str1.length() >= str2.length()) ? str1 : str2;
String minStr = (str1.length() < str2.length()) ? str1 : str2;
for (int i = 0; i < minStr.length(); i++) {
for (int x = 0, y = minStr.length() - i; y <= minStr.length(); x++, y++) {
String subStr = minStr.substring(x, y);
if (maxStr.contains(subStr)) {
subStrs.add(subStr); // 如果符合则添加到subStrs中,继续遍历该长度的其他子串
}
}
if (!subStrs.isEmpty()) {
return subStrs;
} // 只要subStrs非空,则表明已找到最长子串,直接返回subStrs
}
return null;
}
测试代码及运行结果如下:
@Test
public void testGetMax(){
String str1 = new String("ababcdefghcabcabcsgasahellosf");
String str2 = new String("agabcdefghssagahellosfa");
System.out.println(getMaxSameString(str1,str2));
}
运行结果:
[abcdefgh, ahellosf]