来看看这个函数的时间复杂度是多少

2016-12-26 00:16:20 +08:00
 lxiange

不要紧张,请看代码:

void foo1(int n) {
	int bar = 0;
	for (int i = 0; i < n; i++) {
		bar++;
	}
}

请问foo1的时间复杂度?:P

13149 次点击
所在节点    程序员
168 条回复
muziki
2016-12-26 13:05:49 +08:00
@lxiange 明白了,自己大意把问题想随便了,之前没好好说话,抱歉
lxiange
2016-12-26 13:07:46 +08:00
@neoblackcap
如果我偏要和你钻牛角尖,我可以说一个字符串最长也就 4G 啊( 32 位机器上),依然是有限的(即使你把全人类可用的内存都用上,那也是有限的内存)。无论你设计什么数据结构,只要在现实中实现,那一定是有限的位数,那么它的最坏时间复杂度,就是最坏情况下需要的那个时间——那个常数。所以依然是常数时间。

ok ,假设不讨论内存有限的问题,完全按照你描述的理想情况,那你其实就是在模拟一个图灵机咯!你是在佐证我的观点。
事实上,讨论算法计算时间复杂度,就不应该去管实际实现上的种种限制,而单就这个模型去思考。
neoblackcap
2016-12-26 13:17:59 +08:00
@lxiange
显然事实就是这样,但是有限并不是因为 32bit 的限制,有限是因为现实资源有限。
我是没想到这个梗居然还可以佐证你的观点。
ipoh
2016-12-26 13:24:51 +08:00
@lxiange 你错了,我们现在一般考虑算法时间复杂度(包括你的考研题目)都是有限制的,有前提条件的。单纯这个题目而言根本涉及不到你那么多所谓的概念,用这个来装就显得幼稚了。
jsq2627
2016-12-26 13:25:46 +08:00
ipoh
2016-12-26 13:27:00 +08:00
@lxiange 考研题是这个 while (sum < n) { sum += i++;}
ipoh
2016-12-26 13:29:43 +08:00
@jsq2627 那加法就不是 O(1)咯?
jsq2627
2016-12-26 13:34:49 +08:00
我试着解释一下
平时我们说的时间复杂度“ O(关于 n 的一个表达式)”里面 n 的定义是这样的:
The size of the input to a problem is the number of bits required to write out that input.
而此考研题目的精妙之处在于混淆输入数值 n 和上述输入尺寸 n 的概念。

假设把题目那个函数里面的 n 都替换成 x 作为变量名。
x=2^n ( n 是 x 的二进制位数)
于是时间复杂度为 O(x)即 O(2^n)
ipoh
2016-12-26 13:36:35 +08:00
@jsq2627 考研题是这个 while (sum < n) { sum += i++;} 不是楼主贴的
而答案是 根号 n
你再想想
jhdxr
2016-12-26 13:46:14 +08:00
@qwsqwa
@lxiange 然而『伪多项式时间』( https://zh.wikipedia.org/wiki/%E4%BC%AA%E5%A4%9A%E9%A1%B9%E5%BC%8F%E6%97%B6%E9%97%B4 )中的例子似乎无法说明你们的观点。

在素性测试中,使用较小的整数逐个对被测试数进行试除的算法被认为是一个伪多项式时间算法。对于给定的整数 N ,使用从最小的素数 2 开始,到 N {\displaystyle {\sqrt {N}}} \sqrt{N}为止的整数依次对 N 进行试除,如果均无法整除 N ,则 N 是素数,这个过程需要进行至多约 N {\displaystyle {\sqrt {N}}} \sqrt{N}次整数除法,即其时间复杂度为 O ( N ) {\displaystyle O({\sqrt {N}})} O({\sqrt {N}}),为 N 的多项式。令 D 为 N 的二进制表示的位数,那么 N 可以表示为以 2 为底 D 的幂,因此素性测试问题的时间复杂度用 D 表示应为 O ( 2 D / 2 ) {\displaystyle O(2^{D/2})} O(2^{{D/2}})。因此,上述算法是一个伪多项式时间算法。

在这例子中针对 N 和 D 这两个不同的定义,给出了两个不同的时间复杂度的结果。
reus
2016-12-26 13:50:06 +08:00
@jsq2627 他连题目都给人偷换了,还讨论什么。考研出题的人就是正常思路的人,原题就是根号 N ,因为步进不断变大。而他所谓的“简化”,简化成了 O(n)的,还各种偷换概念狡辩……
jedihy
2016-12-26 13:58:34 +08:00
这个不管是怎样的,你都不能说 O(n)是错的,如果 n == variable in the input
jedihy
2016-12-26 13:59:37 +08:00
他的时间复杂度不管怎么算,最会都会等于 O(2^m) = O(n)。
jhdxr
2016-12-26 14:04:06 +08:00
就顶楼那个例子,我还想延伸一步
```
void foo(int[] arr) {
int bar = 0;
for (int i = 0; i < arr.length; i++) {
bar++;
}
}
```

这个例子时间复杂度又是多少呢?

又或者按照我在#130 楼里所指出的那样,如果我的回答是『对于给定的正整数 n ,它的时间复杂度为 O(n)』,这样子的回答是否正确呢?
jsq2627
2016-12-26 14:05:05 +08:00
@jhdxr 时间复杂度特指后者用 D 表示的形式。 wiki 上语言表达有些不严谨,前者 O(根号 n)不能称为“时间复杂度”,只能叫做运行时间与 n 的关系。 wiki 后面特别强调“因此素性测试问题的时间复杂度用 D 表示应为 {\displaystyle O(2^{D/2})} O(2^{{D/2}})”。我想也许是翻译导致这个不严谨的产生。(不过英文原文我并没有找到同样的解释)
v2exhehehehe
2016-12-26 14:07:45 +08:00
金币赚得好开心
lxiange
2016-12-26 14:08:09 +08:00
@linboki 好吧,就按你对装逼的定义,我是在装逼。那你看我这次装逼还成功不 :P

@ipoh @reus @jsq2627 请看 13 楼,我订正过了。
4 楼的代码是我临时直接手写的,并且 v2 不能编辑,所以非常不好意思。

不过其实没有大的影响,
while (sum < n) { sum += i++;}

for (int i = 0; i < n; i++) {bar++;}
在时间复杂度上都是一样的。
(根号 2)^n 和 2^n ,以及 10^n ,没有本质区别。

(虽然在错误的理解下,一个是 O(n),一个是 O(根号 n))

此外,@ipoh 在 124 楼的回复。
计算复杂性理论只是讨论算法的,绝对不应该去考虑现实限制的(当然工程师都一定忍不住去考虑)。

因为讨论的是算法的理论性质,和具体计算机无关,摘自维基:
“计算复杂性理论通过引入数学计算模型来研究这些问题以及定量计算解决问题所需的资源,
....计算复杂性理论的一个作用就是确定一个能或不能被计算机求解的问题的所具有的实际限制。”
喏,不能本末倒置啊,讨论计算复杂性时,是不需要考虑限制的。

并且就算有实际限制,也和是 O(n)还是 O(2^n)无关的啊。
这是不小心引出的另一个话题,限制 32bit 的话,那就都变成 O(1)了。


@jhdxr 所以,为什么叫作“伪”多项式时间?
里面不是有这句话么:
“因此素性测试问题的时间复杂度用 D 表示应为 O ( 2 D / 2 ) {\displaystyle O(2^{D/2})} O(2^{{D/2}})”


@reus
@jedihy
https://en.wikipedia.org/wiki/Time_complexity

“ In computer science, the time complexity of an algorithm quantifies the amount of time taken by an algorithm to run as a function of the length of the string representing the input.”

看看我有木有偷换概念,以及 n 应该代表什么。
jedihy
2016-12-26 14:09:04 +08:00
就算在顶级的 TCS 期刊, TALG 和 TOCS 上,都会简易的指出该算法的时间复杂度是 O(n),这决定于 n 是怎么定义的。你可以考到大多数 NPC 问题的伪多项式时间算法的 big O 都是这么标注的,如背包, subset sum partition 。当然你说 O(2^n)也是绝对正确,但一切的前提是你必须给出一个严格的定义, O(2^n)这个结论本身就是基于很多严谨的假设基础上才得出的,你不能随便一指就说是 O(2^n)。
jecvay
2016-12-26 14:11:03 +08:00
@lxiange 令 D 为 N 的二进制表示的位数, 所以你的 n 代表什么
jedihy
2016-12-26 14:12:05 +08:00
@lxiange 你依然还是不明白什么是 n ,什么是 the length of the string representing the input ,这些都基于你怎么定义的。在没有明确定义 n 的时候, O(2^n) has nothing to do with the given program.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://yangjunhui.monster/t/330114

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX