Java 算法,大O表示法:这个函数是O(n^2)吗?还是O(n)?
这是一本算法书中的代码,“Java中的数据结构和算法,第6版”,作者:Michael T.GoodRich、Roberto Tamassia和Michael H.GoldwasserJava 算法,大O表示法:这个函数是O(n^2)吗?还是O(n)?,java,algorithm,big-o,Java,Algorithm,Big O,这是一本算法书中的代码,“Java中的数据结构和算法,第6版”,作者:Michael T.GoodRich、Roberto Tamassia和Michael H.Goldwasser public static String repeat1(char c, int n) { String answer = ""; for(int j=0; j < n; j++) { answer += c; } return answer; }
public static String repeat1(char c, int n)
{
String answer = "";
for(int j=0; j < n; j++)
{
answer += c;
}
return answer;
}
publicstaticstringrepeat1(字符c,int-n)
{
字符串答案=”;
对于(int j=0;j
根据作者的说法,该算法的大O表示法是O(n^2),原因如下:
命令answer+=c是answer=(answer+c)的简写
命令不会导致将新字符添加到现有字符串中
实例;而是生成一个具有所需序列的新字符串
字符,然后重新分配变量answer,以引用该新变量
就效率而言,这种解释的问题是
连接后创建新字符串需要时间
这与结果字符串的长度成正比
通过此循环,结果的长度为1,第二次通过循环
结果的长度为2,依此类推,直到我们到达长度的最后一个字符串
n、 "
然而,我不明白,这段代码怎么会有O(n^2),因为不管n的值是多少(不包括j感谢您的支持。复杂度变为O(n^2)因为每次字符串的长度增加1,并在每次需要
n
复杂度时创建它。此外,外部循环的复杂度为n
。因此确切的复杂度将为(n*(n+1))/2,即O(n^2)
比如说,
对于abcdefg
a // one length string object is created so complexity is 1
ab // similarly complexity is 2
abc // complexity 3 here
abcd // 4 now.
abcde // ans so on.
abcdef
abcedefg
现在,您可以看到总的复杂性是1+2+3+4+…+n=(n*(n+1))/2。在大O表示法中,它是O(n^2)在循环的每次迭代中,语句
answer+=c;
必须将字符串answer
中已经存在的每个字符复制到一个新字符串中
例如,n=5,c=5
- 第一个循环:
是一个空字符串,但它仍然必须创建一个新字符串。有一个操作可以附加第一个answer
,而'5'
现在是answer
“5”
- 第二个循环:
现在将指向一个新字符串,将第一个answer
复制到一个新字符串,并附加另一个'5'
,以使'5'
。不仅创建了一个新的'55
,还从上一个字符串复制了一个字符字符串
,并追加了另一个'5'
。追加了两个字符'5'
- 第n个循环:
现在将指向一个新字符串,将n-1个answer
字符复制到一个新字符串,并附加一个'5'
字符,以生成一个包含n5的字符串'5'
在Java中,在循环中构造这样的字符串的有效方法是使用
StringBuilder
,使用一个可变的对象,并且不需要每次在每个循环中追加一个字符时复制所有字符。使用StringBuilder
的成本为O(n).字符串在Java中是不可变的。我认为这段糟糕的代码是O(n^2),正是因为这个原因,而且只有这个原因。每次迭代时它都必须构造一个新字符串。我不确定字符串串联是否与字符数成真正的线性比例(因为字符串的长度已知,所以它似乎应该是一个常数时间操作)。但是,如果您接受作者的说法,然后迭代n次,每次迭代的时间与n成正比,则得到n^2。StringBuilder将为您提供O(n)。这是因为:
answer += c;
是一个字符串
串联。在java中,字符串
是不可变的
这意味着连接的字符串是通过创建原始字符串的副本并将c
附加到它来创建的。因此,对于n
大小string
,一个简单的连接操作是O(n)
在第一次迭代中,答案长度为0
,在第二次迭代中答案长度为1
,在第三次迭代中答案长度为2,依此类推
所以你每次都在做这些操作
1 + 2 + 3 + ... + n = O(n^2)
对于字符串操作,
StringBuilder
是首选方法,即它在O(1)
时间中附加任何字符。将字符串的长度视为“n”,因此每次我们需要在末尾添加元素,因此字符串的迭代为“n”,并且我们还有外部For循环,因此为“n”,因此我们得到O(n^2).我基本上同意它在实践中是O(n^2),但考虑到:
Java是聪明的。在许多情况下,它使用StringBuilder而不是string来进行隐藏的连接。你不能假设它每次都要复制底层数组(尽管在这种情况下几乎肯定会)
Java变得越来越智能,这是没有理由的