【问题标题】:finding all distinct substring of a string查找字符串的所有不同子字符串
【发布时间】:2012-10-24 04:58:21
【问题描述】:

大家好,我遇到了家庭作业问题,它要求我找到字符串的所有不同子字符串。 我已经实现了一种方法,它会告诉你字符串的所有子字符串,但我需要帮助弄清楚如何不计算一个已经被计算为子字符串的子字符串,因为分配是要找到不同的子字符串。

public int printSubstrings1(int length)
{ 
    for(int i=0; i<text.length()-length+1;i++)
    {
        String sub = text.substring(i,length+i);

        counter++;
    }
    return counter;

}

在这里,我从给定的字符串中传递我想要的子字符串的长度。 我正在通过另一种方法做到这一点。

所以给出的示例字符串是“fred”,而不是不同的子字符串将是 10。我的方法将输出正确答案,因为字符串不包含任何重复的字母。我被困在我确实得到重复子字符串的部分。

如果我输入弗雷德。这是我的方法将输出的内容

长度 1
f
r
电子
d
长度 2
FR
重新

长度 3
免费
红色
长度 4
弗雷德

【问题讨论】:

  • 将它们放在Set 中——“Set 是不包含重复元素的集合”
  • 好主意谢谢你的意思是数组正确。比我如何检查字符串中是否已经存在。因为数组没有 .在它的类中包含方法。
  • 你能提供Set的例子吗?
  • java.util.HashSet,例如。

标签: java string substring


【解决方案1】:

有两种方法可以做到这一点,不确定你的老师是否允许,但我将使用 HashSet 来保证唯一性。

不使用'substring()':

void uniqueSubStrings(String test) {
HashSet < String > substrings = new LinkedHashSet();
char[] a = test.toCharArray();
for (int i = 0; i < test.length(); i++) {
    substrings.add(a[i] + "");
    for (int j = i + 1; j < test.length(); j++) {
        StringBuilder sb = new StringBuilder();
        for (int k = i; k <= j; k++) {
            sb.append(a[k]);
        }
        substrings.add(sb.toString());
    }
}
System.out.println(substrings);

}

使用“子字符串”:

    void uniqueSubStringsWithBuiltIn(String test) {
    HashSet<String> substrings = new LinkedHashSet();

    for(int i=0; i<test.length();i++) {
        for(int j=i+1;j<test.length()+1;j++) {
            substrings.add(test.substring(i, j));
        }
    }
        System.out.println(substrings);}

【讨论】:

    【解决方案2】:

    我关注了这个link.Acknowledged from similar answer in quora

    解决方案包括构建后缀数组,然后根据最长公共前缀查找不同子字符串的数量。

    这里的一个关键观察是:

    如果你查看一个字符串的每个后缀的前缀,你已经覆盖了该字符串的所有子字符串。

    举个例子:香蕉

    后缀为:0) BANANA 1) ANANA 2) NANA 3) ANA 4) NA 5) A

    如果我们对上面的一组后缀进行排序,遍历前缀会容易得多,因为我们可以轻松跳过重复的前缀。

    排序的后缀集:5) A 3) ANA 1) ANANA 0) BANANA 4) NA 2) NANA

    从现在开始,

    LCP = 2 个字符串的最长公共前缀。

    初始化

    ans = length(第一个后缀) = length("A") = 1.

    现在考虑上述一组排序后缀中的连续后缀对,即 [A, ANA]、[ANA, ANANA]、[ANANA, BANANA] 等。

    我们可以看到,LCP("A", "ANA") = "A"。

    所有不属于公共前缀的字符都构成一个不同的子字符串。在上述情况下,它们是“N”和“A”。所以应该将它们添加到ans中。

    所以我们有,1 2 ans += length("ANA") - LCP("A", "ANA") ans = ans + 3 - 1 = ans + 2 = 3

    对下一对连续的后缀执行相同操作:["ANA", "ANANA"]

    1 2 3 4 LCP("ANA", "ANANA") = "ANA"。 ans += length("ANANA") - length(LCP) => ans = ans + 5 - 3 => ans = 3 + 2 = 5。

    同样,我们有:

    1 2 LCP("ANANA", "BANANA") = 0 ans = ans + length("BANANA") - 0 = 11

    1 2 LCP("BANANA", "NA") = 0 ans = ans + length("NA") - 0 = 13

    1 2 LCP("NA", "NANA") = 2 ans = ans + length("NANA") - 2 = 15

    因此字符串“BANANA”的不同子字符串的数量 = 15。

    【讨论】:

      【解决方案3】:

      此算法仅使用 Z 函数 / Z 算法。

      对于单词的每个前缀 i,将其反转并对其执行 z_function。 以i 结尾的新的不同子字符串的数量是(the length of the prefix) — (maximum value in the z_function array)。 伪代码如下所示:

      string s; cin >> s;
      int sol = 0
      foreach i to s.size()-1
          string x = s.substr( 0 , i+1 );
          reverse( x.begin() , x.end() );
          vector<int> z = z_function( x );
          //this works too
          //vector<int> z = prefix_functionx(x); 
          int mx = 0;
          foreach j to x.size()-1
              mx = max( mx , z[j] );
          sol += (i+1) - mx; 
      
      cout << sol;
      

      这个算法的时间复杂度是O(n^2)。 z_function 也可以返回最大值。

      Source.

      这不是我原来的答案。我只是链接到它并粘贴它以防链接失效。

      【讨论】:

        【解决方案4】:
        public ArrayList<String> getAllUniqueSubset(String str) {
                ArrayList<String> set = new ArrayList<String>();
                for (int i = 0; i < str.length(); i++) {
                    for (int j = 0; j < str.length() - i; j++) {
                        String elem = str.substring(j, j + (i+1));
                        if (!set.contains(elem)) {
                            set.add(elem);
                        }
                    }
                }
                return set;
            }
        

        【讨论】:

        • 如果您添加一些 cmets,您的回答会更有帮助
        【解决方案5】:

        这里是Set的示例

        public int printSubstrings1(int length) {
            Set<String> set = new HashSet<String>();
            for(int i=0; i < text.length() - length + 1; i++) {
                String sub = text.substring(i,length+i);
                set.add(sub);
            }
            for (String str : set) {
                System.out.println(str);
            }
            return set.size();
        }
        

        【讨论】:

          【解决方案6】:

          将任何新的子字符串插入数组并检查它是否已经可用,否则不要将其添加到数组中。完成后循环遍历数组并打印出不同的子字符串。

          要检查数组中是否存在元素,请创建一个以数组和值作为参数的函数。如果找到返回true,它将遍历数组以查找值。循环外返回false。

          例如

          public static boolean(String target, String[] arr)
          {
            for(int i = 0; i < arr.length; i++){
                if(arr[i].equals(target))
                   return true;
            }
             return false;
          }
          

          【讨论】:

          • 如果你的数组有未初始化的单元格,这将抛出一个NullPointerException
          猜你喜欢
          • 1970-01-01
          • 2013-07-01
          • 2017-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-07-04
          • 2013-03-22
          • 2012-09-07
          相关资源
          最近更新 更多