问题描述
我有以下算法:
for(int i = 1; i < n; i++)
for(int j = 0; j < i; j++)
if(j % i == 0) System.out.println(i + " " + j);
这将运行max(n,0)
次。
Big-O表示法是O(n)
吗?如果不是,那是什么,为什么?
谢谢。
解决方法
您尚未说明要使用Big-O表示法测量的内容。假设它是时间复杂度。接下来,我们必须定义要用来衡量复杂度的因变量。此处的合理选择是n
的绝对值(与位长相反),因为您要处理的是固定长度的int
,而不是任意长度的整数。
您是正确的,println
被执行O(n)次,但这是在计算命中某行的频率,它并不能衡量时间复杂度。
很容易看到if
语句被命中O(n^2)
次,因此我们已经确定时间复杂度从下方受到Omega(n^2)
的限制。正如评论者已经指出的那样,如果条件仅对j=0
为真,那么我怀疑您实际上是在写i % j
而不是j % i
吗?这很重要,因为println(i + " " + j)
语句的时间复杂度当然不是O(1)
,而是O(log n)
(您可能无法用少于{{1}的字符来打印x
字符}步骤),因此乍一看,总体复杂度可能比x
差。
假设您打算编写O(n^2)
,我们可以简化假设条件始终为真,在这种情况下,我们将获得严格比{{1 }}!
但是,注意到i % j
的除数的数量受O(n^2 log n)
的限制,我们实际上有O(n^2)
。但是自n
起,这等于O(Sqrt(n))
。
您可以更深入地研究数论,以找到除数的tighter bounds,但这没什么区别,因为O(n^2 + n*Sqrt(n)*log(n))
仍然是主要因素。
因此,最严格的上限确实是O(Sqrt(n) * log(n)) < O(n)
,但并不像乍看起来那样明显。
max(n,0)
的确是O(n)
。但是,您的算法在O(n**2)
中。您的第一个循环进行了n
次,而第二个循环进行了i
次,平均n/2
。这就是O(n**2 / 2) = O(n**2)
。但是,与算法的运行时间不同,println
达到的次数是O(n)
,因为恰好发生n
次。
因此,答案取决于您要精确测量的范围。