我一直以为:
的复杂性 1 + 2 + 3 + ... + n
是O(n),并且将两个n乘n矩阵求和为O(n ^ 2)。
但是今天我从教科书中读到“通过前n个整数之和的公式,这是n(n + 1)/ 2”,然后是:(1/2)n ^ 2 +(1 / 2)n,因此O(n ^ 2)。
我在这里缺少什么?
答案 0 :(得分:17)
big O notation可用于确定任何功能的增长率。 p>
在这种情况下,本书似乎并不是在谈论计算价值的时间复杂性,而是关于价值本身。 n(n+1)/2
是O(n^2)
。
答案 1 :(得分:8)
您混淆运行时的复杂性和结果的大小(复杂性)。
求和的运行时间,一个接一个,第一个 n 连续数字确实是 O ( n )。 1
但结果的复杂性,即“从1到 n ”的大小= n ( n - 1) / 2是 O ( n ^ 2)。
1 但是对于任意大的数字,这是简单的,因为添加大数字需要比添加小数字更长的时间。对于精确的运行时分析,您确实必须考虑结果的大小。然而,这通常与编程无关,甚至在纯粹的理论计算机科学中也是如此。在这两个域中,求和数通常被视为 O (1)操作,除非域明确要求(即实现bignum库的操作时)。
答案 2 :(得分:7)
n(n + 1)/ 2是对N个整数的连续序列求和的快速方法(从1开始)。我认为你的算法混淆了一个大哦符号!
如果你认为它是一个函数,那么这个函数的复杂性就是O(1):
public int sum_of_first_n_integers(int n) { return (n * (n+1))/2; }
天真的实现会有很大的O(n)复杂性。
public int sum_of_first_n_integers(int n) {
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += n;
}
return sum;
}
即使仅查看单个n×n矩阵的每个单元格也是O(n ^ 2),因为矩阵具有n ^ 2个单元格。
答案 3 :(得分:4)
所以我的猜测是,这实际上是对Cracking the Coding Interview的引用,该段落在StringBuffer
实现中:
在每个连接上,创建一个新的字符串副本,然后创建 两个字符串被逐个字符地复制。首先 迭代要求我们复制
x
个字符。第二次迭代 需要复制2x
个字符。第三次迭代需要3x
,和 等等。因此总时间为O(x + 2x + ... + nx)
。这减少了 到O(xn²)
。 (为什么不是O(xnⁿ)
?因为1 + 2 + ... n
等于n(n+1)/2
或者,O(n²)
。)
无论出于何种原因,我在第一次阅读中发现这有点令人困惑。需要注意的重要一点是,n
正在乘以n
,换句话说n²
正在发生,并且占据主导地位。这就是为什么最终O(xn²)
只是O(n²)
- x
有点像红鲱鱼。
答案 4 :(得分:2)
确实没有问题的复杂性,而是算法的复杂性。
在您的情况下,如果您选择迭代所有数字,那么复杂性确实是O(n)
。
但这不是最有效的算法。更有效的方法是应用公式 - n*(n+1)/2
,它是常量,因此复杂度为O(1)
。
答案 5 :(得分:1)
您的公式不依赖于要添加的数字的数量,因此它是常量时间算法,或O(1)。
如果你一次添加一个数字,那么它确实是O(n)。公式是捷径;这是一种不同的,更有效的算法。当添加的数字全部为1 .. n 时,快捷方式有效。如果你有一个非连续的数字序列,那么快捷方式不起作用,你将不得不回到逐个算法。
但这些都不适用于数字矩阵。要添加两个矩阵,它仍然是O(n ^ 2),因为你要添加n ^ 2个不同的数字对来得到n ^ 2个结果的矩阵。
答案 6 :(得分:0)
对N个任意整数求和和求和N之间存在差异。对于1 + 2 + 3 + 4 + ... + N,您可以利用它们可以被分成具有公共和的对的事实,例如, 1 + N = 2+(N-1)= 3+(N-2)= ... = N + 1.因此,这是N + 1,N / 2次。 (如果有一个奇数,其中一个将被取消配对,但只需稍加努力就可以看到在这种情况下同样的公式。)
但是,这不是O(N ^ 2)。它只是使用 N ^ 2的公式,实际上是O(1)。对于大N,O(N ^ 2)意味着(大致)计算它的步数增加如N ^ 2.在这种情况下,无论N如何,步数都是相同的。答案 7 :(得分:0)
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += n;
}
return sum;
类似于1 + 2 + 3 + 4 + ...... + n。在这种情况下,算法的复杂度被计算为执行加法运算的次数,即O(n)。
找到n个自然数的序列之和的答案的第二种方法是最直接的公式n *(n + 1)/ 2。这个公式使用乘法而不是重复加法。乘法运算没有线性时间复杂度。有多种可用于乘法的算法,其时间复杂度范围从O(N ^ 1.45)到O(N ^ 2)。因此,在乘法时间复杂度取决于处理器的架构。但是为了分析目的,乘法的时间复杂度被认为是O(N ^ 2)。因此,当使用第二种方式找到总和时,时间复杂度将为O(N ^ 2)。
这里的乘法运算与加法运算不同。如果有人掌握计算机组织学科的知识,那么他就可以很容易地理解乘法和加法运算的内部工作。乘法电路比加法器电路更复杂,并且需要比加法器电路更高的时间来计算结果。所以系列之和的时间复杂度不能保持不变。
答案 8 :(得分:0)
添加前n个数字:
考虑算法:
Series_Add(n)
return n*(n+1)/2
该算法确实在 O(| n | ^ 2)中运行,其中| n |是n的长度(位)而不是大小,仅是因为2个数字(k个位之一和另一个l位)的相乘是在 O(k * l)时间内进行的。>
小心
考虑此算法:
Series_Add_pseudo(n):
sum=0
for i= 1 to n:
sum += i
return sum
这是一种幼稚的方法,您可以假定此算法以线性时间或通常以多项式时间运行。事实并非如此。
n的输入表示(长度)是O(logn)位(除一进制以外的任何n进制编码),并且该算法(尽管其幅度线性地运行)<指数>指数运行输入长度的(2 ^ logn)。 这实际上是伪多项式算法的情况。它似乎是多项式,但不是。
您甚至可以在python(或任何编程语言)中尝试使用中等长度的数字(例如200位)。
应用第一种算法,结果很快就得到了解决,而应用第二种算法,则必须等待一个世纪...
答案 9 :(得分:0)
1 + 2 + 3 + ... + n始终小于n + n + n ... + n次。您可以将此n + n + .. + n重写为n * n。
如果存在一个正整数n0和一个正整数,则f(n)= O(g(n)) 常数c,使得f(n)≤c * g(n)∀n≥n0
因为Big-Oh代表函数的上限,其中函数f(n)是自然数之和,直到n。
现在,在谈论时间复杂性时,对于少量数字,加法应该是恒定的工作量。但是n的大小可能很大。您不能否认这种可能性。
adding integers can take linear amount of time when n is really large.。因此,您可以说加法是O(n)运算,并且您要添加n个项目。这样就可以使它成为O(n ^ 2)。当然,它并不总是需要n ^ 2的时间,但是当n很大时,这是最坏的情况。 (上限,记得吗?)
现在,假设您直接尝试使用n(n + 1)/ 2来实现它。只是一个乘法和一个除法,这应该是一个常数运算,不是吗? 不。
使用位数的自然大小度量,使用长乘法将两个n位数字相乘的时间复杂度为Θ(n ^ 2)。当用软件实现时,长乘法算法必须处理加法期间的溢出,这可能很昂贵。 Wikipedia
这又使我们变成O(n ^ 2)。