Java中的字符串重复大O附加

时间:2018-12-23 05:12:09

标签: java big-o stringbuilder

我有一个函数来获取一个字符串,作为原始字符串的重复。我想知道是否使用StringBuilder append,函数的Big O是什么?是O(nl):n是重复次数,l是原始字符串的长度吗?

public String getRepetition(String originalStr, Integer n){
    StringBuilder str = new StringBuilder();
    for(int i = 0; i < n; i++)
        str.append(originalStr);
    return str.toString();
}

与下面的方法相比,哪个更好?

public String getRepetition(String originalStr, Integer n){
    String str = "";
    for(int i = 0; i < n; i++)
        str += originalStr;
    return originalStr;
}

3 个答案:

答案 0 :(得分:3)

我不确定为什么其他三个答案都说这两段代码都是O(n)。假设originalStr不是"",则第一个是O(n),另一个是O(n ^ 2)! (这是一种感叹,而不是阶乘。)他们在Java入学的第一天就教授了这一点。 C程序员会“在该strlen循环的情况下不要使用for”; Java程序员可以做到这一点。

String str = "";
for(int i = 0; i < n; i++)
    str += originalStr;

此循环str周围的时间越来越长。是i * orginalStr.length()。创建一个新的String(假设没有 wild 编译器优化),每次所花费的时间与i大致成比例。

编辑:通常,我们会忽略原始字符串的长度。但是,是的,这当然将是比例性的,因此O(n strlen(originalStr))和O(n n * strlen(originalStr))。按照惯例,这是单独处理的。

如果我们在没有String抽象的情况下重写代码,也许会更清楚。

public static char[] getRepetition(char[] originalStr, int n) {
    char[] str = {};
    for (int i = 0; i < n; ++i) {
        assert str.length == i * originalStr.length;
        char[] newStr = new char[str.length + originalStr.length];
        for (int j=0; j<str.length; ++j) {
            newStr[j] = str[j];
        }
        for (int j=0; j<originalStr.length; ++j) {
            newStr[str.length+j] = originalStr[j];
        }
        str = newStr;
    }
    return str;
}

(和以往一样,我不必花太多时间去编译代码。在核反应堆中使用它并不安全。)

只是为咯咯笑,我们就介绍一下第一个实现。

public static char[] getRepetition(char[] originalStr, int n) {
    char[] str = new char[16];
    int strLen = 0;
    for (int i = 0; i < n; ++i) {
        assert strLen == i * originalStr.length;
        // ensureCapacity
        if (str.length < strLen + originalStr.length) {
            // The size at least doubles, 
            //   so this happens increasing less often.
            // It wont happen again for approximately
            //   the same number of iterations
            //   as have already happened!
            char[] newStr = new char[Math.min(
                str.length + originalStr.length, // first time safe
                str.length*2 + 2                 // *2 !
            )];
            for (int j=0; j<strLen; ++j) {
                newStr[j] = str[j];
            }
            str = newStr;
        }
        // actual append
        for (int j=0; j<originalStr.length; ++j) {
            str[strLen++] = originalStr[j];
        }
    }
    // toString
    char[] newStr = new char[strLen];
    for (int i=0; j<newStr.length; ++i) {
         newStr[i] = str[j];
    }
    return newStr;
}

答案 1 :(得分:2)

您的两种方法均为O(n),而第一种方法则消除了几个临时String。不清楚为什么将n设为Integer,也为什么不将其设为static方法(不取决于实例状态)还不清楚。另外,在Java 8+中,您可以使用lambda来实现它,例如

public static String getRepetition(String originalStr, int n) {
    return Stream.generate(() -> originalStr).limit(n).collect(Collectors.joining());
}

此外,如果您要像第一个示例一样使用StringBuilder,则可以显式调整其大小,以避免摊销调整StringBuilder大小的成本。

StringBuilder str = new StringBuilder(originalStr.length() * n);

答案 2 :(得分:1)

在这两种情况下,复杂度均为O(n),因为您要迭代n次。

第二种方法的唯一区别是您在每次迭代中(即在String处创建新的str += originalStr;