如何有效地形成后缀数组?

时间:2013-04-16 11:24:04

标签: java string

我一直在寻找方法在Java上制作后缀数组 我发现了两种能力变种。此外,我希望更深入地了解这些变体之间的差异 包括running time& space

代码(后缀):

public static String[] suffixes(String s)
{
int N = s.length();
String[] suffixes = new String[N];
for (int i = 0; i < N; i++)
suffixes[i] = s.substring(i, N);
return suffixes;
}

代码(StringBuilder后缀):

public static String[] suffixes(String s)
{
int N = s.length();
StringBuilder sb = new StringBuilder(s);
String[] suffixes = new String[N];
for (int i = 0; i < N; i++)
suffixes[i] = sb.substring(i, N);
return suffixes;
}

问题:

  • 如何有效地形成后缀数组?

5 个答案:

答案 0 :(得分:3)

您描述的两种执行方式之间没有明显区别:由于Java中的String不可变,因此将为每个后缀创建一个新对象。与设置新字符串对象所需的分配和复制相比,从StringStringBuilder建立子字符串不会给您带来太大的性能差异。

当您查找后缀时,不需要传递结束索引:使用单个int的重载:

for (int i = 0; i < N; i++)
    suffixes[i] = s.substring(i);

答案 1 :(得分:0)

您的代码段之间的唯一区别是使用String或StringBuilder,您也只是使用它来检索子字符串。
来自StringBuilder的subString()

 new String(offset + beginIndex, endIndex - beginIndex, value);  
来自String的

subString()

 new String(offset + beginIndex, endIndex - beginIndex, value);  

两者都相同并创建新的String,因此性能不会有任何差异

答案 2 :(得分:0)

最有效的方法是使用char数组。但是,它最重要的操作是创建String对象,它不会那么重要。

String s = "foobarbaz"; 
char[] cha = s.toCharArray();
int length = cha.length;
String[] suffixes = new String[length];
for (int i = 0; i < length; ++i)
  suffixes[i] = new String(cha, i, length-i);

答案 3 :(得分:0)

你可以这样做,这避免了子串方法,

public String[] suffix(String s)
{
    String[] suffixes = new String[s.length()];
    String suffix = null;
    for (int i = 0 ; i < s.length() ; i++)
    {
        suffix = suffix == null ? "" + s.charAt(i) : suffix + s.charAt(i);
        suffixes[i] = suffix;
    }

    return suffixes;
}

不确定它是否更快。

答案 4 :(得分:0)

最后,您总是需要n + 1个字符串才能完成此任务。只有可以优化的东西才是创建这些对象的时间。

您可以将字符串表示形式创建为char数组,并且lazy(按需)返回后缀。

您可以使用Iterable和Iterator接口来执行此操作:

public class StringSufixies implements Iterable<String> {

    private final String input; 

    public StringSufixies(String input) {
        this.input = input;
    }

    @Override
    public Iterator<String> iterator() {
        return new SuffixStringIterator(input);
    }

    private static class SuffixStringIterator implements Iterator<String> {

        private final String input;
        private final int size;
        private int suffixId;

        private SuffixStringIterator(String input) {
            this.input = input;
            this.size  = input.length();
            this.suffixId = 1;
        }

        @Override
        public boolean hasNext() {
            return suffixId <= size;
        }

        @Override
        public String next() {
            return input.substring(0, suffixId++); //At this point we create new String
        }

        @Override
        public void remove() {
            //Add throw or other impl
        }

    }

}

您可以在char数组上实现关键功能。

private static class SuffixCharIterator implements Iterator<String> {

private final char[] charSequence;
private final int size;
private int suffixId = 0;

private SuffixCharIterator(char[] charSequence) {
    this.charSequence = charSequence;
    this.size = charSequence.length;
}

@Override
public boolean hasNext() {
    return suffixId <= size;
}

@Override
public String next() {
    return new String(charSequence, 0, suffixId++); //At this point we create a new String
}

@Override
public void remove() {

}

}

但恕我直言更复杂,我们什么也得不到。

此解决方案的优点是您可以处理结果并决定在创建所有前缀之前停止。