我有一个函数来获取一个字符串,作为原始字符串的重复。我想知道是否使用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;
}
答案 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;