Java中的字符串子字符串生成

时间:2012-02-22 19:10:35

标签: java string substring

我试图找到给定字符串中的所有子字符串。对于像rymis这样的随机字符串,子序列为[i, is, m, mi, mis, r, ry, rym, rymi, rymis, s, y, ym, ymi, ymis]。从Wikipedia开始,长度为n的字符串将包含n * (n + 1) / 2个总字符串。

可以通过以下代码片段找到:

    final Set<String> substring_set = new TreeSet<String>();
    final String text = "rymis";

    for(int iter = 0; iter < text.length(); iter++)
    {
        for(int ator = 1; ator <= text.length() - iter; ator++)
        {
            substring_set.add(text.substring(iter, iter + ator));
        }
    }

适用于较小的String长度,但由于算法接近O(n^2),因此对于较大的长度显然会变慢。

同时阅读可以在O(n)进行插入的后缀树并注意到相同的子序列可以通过从右边删除1个字符重复插入子字符串直到字符串为空来获得。哪个应该是O(1 + … + (n-1) + n)summation of n - &gt; n(n+1)/2 - &gt; (n^2 + n)/ 2,又在O(n^2)附近。虽然似乎有一些后缀树可以在log2(n)时间内进行插入,这将是一个更好的因素O(n log2(n))

在我深入研究后缀树之前,这是正确的路线,是否有其他算法可以提高效率,或者O(n^2)是否会达到最佳效果?

3 个答案:

答案 0 :(得分:1)

这是你的例子的倒置方式,但仍然是o(n ^ 2)。

string s = "rymis";
ArrayList<string> al = new ArrayList<string>();
for(int i = 1; i < s.length(); i++){//collect substrings of length i
 for(int k = 0; k < s.length(); k++){//start index for sbstr len i
  if(i + k > s.length())break;//if the sbstr len i runs over end of s move on
  al.add(s.substring(k, k + i));//add sbstr len i at index k to al
 }
}

让我看看我是否可以发布递归示例。我开始做一些递归尝试,并使用双滑动窗口提出这种迭代方法,作为对上述方法的一种改进。我有一个递归的例子,但是在减少树大小方面存在问题。

string s = "rymis";
ArrayList<string> al = new ArrayList<string>();
for(int i = 1; i < s.length() + 1; i ++)
{
 for(int k = 0; k < s.length(); k++)
 {
  int a = k;//left bound window 1
  int b = k + i;//right bound window 1
  int c = s.length() - 1 - k - i;//left bound window 2
  int d = s.length() - 1 - k;//right bound window 2
  al.add(s.substring(a,b));//add window 1
  if(a < c)al.add(s.substring(c,d));//add window 2
 }
}

使用arraylist影响性能时出现了一个问题,因此下一个将使用更基本的结构。

string s = "rymis";
StringBuilder sb = new StringBuilder();
for(int i = 1; i < s.length() + 1; i ++)
{
 for(int k = 0; k < s.length(); k++)
 {
  int a = k;//left bound window 1
  int b = k + i;//right bound window 1
  int c = s.length() - 1 - k - i;//left bound window 2
  int d = s.length() - 1 - k;//right bound window 2
  if(i > 1 && k > 0)sb.append(",");
  sb.append(s.substring(a,b));//add window 1
  if(a < c){
   sb.append(",");
   sb.append(s.substring(c,d));//add window 2
  }
 }
}
string s = sb.toString();
String[] sArray = s.split("\\,");

答案 1 :(得分:1)

我很确定你无法击败O(n ^ 2),正如问题评论中提到的那样。

我对不同的编码方式感兴趣,所以我快速编写了一个,我决定在这里发布。

我放在这里的解决方案并不是渐渐没有我想的那么快,但是当计算内部和外部循环时,它的数量会减少。此处的重复插入次数也较少 - 没有重复的插入。

String str = "rymis";
ArrayList<String> subs = new ArrayList<String>();
while (str.length() > 0) {
    subs.add(str);
    for (int i=1;i<str.length();i++) {
        subs.add(str.substring(i));
        subs.add(str.substring(0,i));
    }
    str = str.substring(1, Math.max(str.length()-1, 1));
}

答案 2 :(得分:1)

我不确定确切的算法,但您可以查看Ropes:

http://en.wikipedia.org/wiki/Rope_(computer_science)

  

总之,当数据很大且频繁修改时,绳索更适合。

我相信Rope在你的问题上胜过String。