当前位置: 首页 > 知识库问答 >
问题:

查找给定两个字符串的所有公共子字符串

公孙国兴
2023-03-14

我遇到了一个问题语句,要在给定的两个子字符串之间找到所有公共子字符串这样一种方式,在每种情况下都必须打印最长的子字符串。问题声明如下:

编写一个程序来查找两个给定字符串之间的公共子字符串。但不包括包含在较长公共子字符串中的子字符串。

    null

在这种情况下,您不必使用字符串实用程序方法,如: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.

试着弄清楚我方法的时间复杂性。

    null

平均值将是这个和除以产生的子字符串总数。

这是一个求和除法问题,其解如下O(n)

因此...

 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;
 }
}
 printCommonSubstrings: Finds all the substrings of S1 and 
                        checks if it is also a substring of 
                        S2.
 isSubstring : As the name suggests, it checks if the given string 
               is a substring of the other string.
  S1 = “neerajisgreat”;
  S2 = “neerajisnotgreat”
  S3 = “rajeatneerajisnotgreat”

共有1个答案

夏侯嘉荣
2023-03-14

您最好使用一个合适的算法来完成任务,而不是使用暴力的方法。维基百科描述了最长公共子串问题的两种常见解决方案:后缀-树和动态-编程。

动态规划求解需要O(n m)时间和O(n m)空间。这是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;
}

现在,您需要所有常见的子字符串,而不仅仅是最长的子字符串。您可以增强此算法以包括更短的结果。让我们检查表中的示例输入eatsleepnightxyzeatsleepabcxyz:

  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
  • EatSleep结果很明显:在左上角有12345678对角线。
  • xyz结果是右下角的123对角线。
  • A结果由顶部附近的1指示(第二行第九列)。
  • T结果由左下角附近的1指示。

我建议只做一遍,只做构建表。然后,进行第二次传递,从右下角向后迭代,以收集结果集。

 类似资料:
  • 给定两个字符串,我想识别从最长到最短的所有公共子字符串。 最后,我需要检查一个字符串与数千个字符串的固定列表。我不确定在散列出这些字符串中的所有子字符串时是否有一个明智的步骤。 先前的答复: 在这个线程中,发现了一个动态编程解决方案,它需要O(nm)时间,其中n和m是字符串的长度。我对一种更有效的方法感兴趣,它将使用后缀树。 背景: 我正在根据旋律片段创作歌曲旋律。有时,一个组合会产生一个旋律,与

  • 问题内容: 我正在尝试从Java字符串中找到所有三个字母子字符串。 例如,从字符串“ example string”中,我应该得到“ exa”,“ xam”,“ amp”,“ mpl”,“ ple”,“ str”,“ tri”,“ rin”,“ ing”。 我尝试使用Java正则表达式“([[a-zA-Z]){3}”,但仅得到“ exa”,“ mpl”,“ str”,“ ing”。 有人可以告诉我

  • 问题内容: 如何找到两个子字符串之间的字符串? 我当前的方法是这样的: 但是,这似乎效率很低而且不合Python。什么是做这样的更好的方法? 忘了提:该字符串可能无法启动,并最终和。他们之前和之后的字符可能更多。 问题答案:

  • 问题内容: 我正在寻找一个Python库,用于从 一组字符串中 找到最长的公共子 字符串 。有两种方法可以解决此问题: 使用后缀树 使用动态编程。 实施的方法并不重要。重要的是,它可以用于 一组字符串 (不仅是两个字符串)。 问题答案: 这些成对的函数将在任意字符串数组中找到最长的公共字符串: 毫无疑问,该算法可以得到改进,而且我对Python的接触也很少,因此也许它在语法上也可能更有效,但是它应

  • 我有一个这样的字符串: 我正在尝试获取任何显示为title(title=“anything here”)的内容。我已经尝试过了,但无法正常工作。

  • 问题内容: 我需要解析一个HTML文档并查找其中所有出现的字符串。 我目前将HTML加载到字符串变量中。我只需要字符位置,这样我就可以遍历列表以在字符串之后返回一些数据。 该函数仅返回第 一个 匹配项。如何 全部 归还呢? 问题答案: 在不使用正则表达式的情况下,类似这样的方法应该可以返回字符串位置: