通过数组的所有可能序列进行迭代的时间复杂度是多少?

时间:2019-05-17 13:58:39

标签: java algorithm time-complexity

一种遍历数组内所有可能的索引序列的算法。

单个循环的时间复杂度是线性的,两个嵌套循环的时间是二次O(n ^ 2)。但是,如果嵌套另一个循环并遍历这两个索引之间分隔的所有索引怎么办?时间复杂度是否上升到三次O(n ^ 3)?当N变得很大时,似乎没有足够的迭代来考虑复杂度三次方,但似乎是二次O(n ^ 2)

这里是考虑N =数组长度的算法

for(int i=0; i < N; i++)
{
    for(int j=i; j < N; j++)
    {
        for(int start=i; start <= j; start++)
        {
          //statement
        }
    }
}

这是N = 7(一直持续到i = 7)时迭代的简单视图:

enter image description here enter image description here

以此类推。

我们应该将时间复杂度视为二次,三次还是不同的大小复杂度?

2 个答案:

答案 0 :(得分:7)

基本

for (int i = 0; i < N; i++) {
    for (int j = i; j < N; j++) {
        // something
    }
}

我们执行something n * (n+1) / 2次=> O(n^2)。关于原因:这是
的简化形式 sum (sum 1 from y=x to n) from x=1 to n

对于您的新案例,我们有一个类似的公式:
sum (sum (sum 1 from z=x to y) from y=x to n) from x=1 to n。结果为n * (n + 1) * (n + 2) / 6 => O(n^3) =>时间复杂度为三次

在两个公式中的1是您输入something成本的地方。特别是在您进一步扩展公式的地方。

请注意,所有索引可能相距一个,我没有特别注意<<=等,

答案 1 :(得分:2)

简短回答O(choose(N+k, N))O(choose(N+k, k))相同。


这是如何到达那里的长答案。

您的基本问题版本正确。使用k嵌套循环,随着O(N^k)趋于无穷大,您的复杂度将为N。但是,随着kN的变化,行为会更加复杂。

让我们考虑相反的极端。假设N是固定的,并且k变化。  如果N为0,则您的时间是常数,因为最外面的循环在第一次迭代时失败。如果N = 1则您的时间为O(k),因为您经历了所有嵌套层次只有一种选择,每次都只有一种选择。如果N = 2发生了一些更有趣的事情,您将一遍又一遍地进行嵌套,这需要时间O(k^N)。通常,在固定N的情况下,时间为O(k^N),其中k的一个因素是遍历嵌套所花费的时间,而O(k^(N-1))则是由于顺序前进。这是意外的对称!

现在,如果kN都很大怎么办?那的时间复杂度是多少?好吧,这可以给您直觉。

我们能否描述到达最内层循环的所有时间?是!  考虑k+N-1个插槽,其中k个被“进入了另一个循环” ,其中N-1个被了“使索引增加了1”。 我声明以下内容:

  1. 这些与1-1对应于我们到达最内层循环的决策序列。通过查看哪些索引比其他索引大多少,可以看出。
  2. “进入另一个循环” 条目是完成此迭代的最内层循环所需要的工作,该循环不会导致其他任何循环迭代。
  3. 如果1 < N实际上需要我们在独特工作中获得的更多收益,那么

现在,这看起来像是一团糟,但是有一个技巧可以使它出乎意料地简化。

诀窍是这个。假设我们采用了其中一种模式,并在最后的“再输入一个循环” 条目的最后一段中的某个位置插入了一个额外的“将索引提高1” 。有多少种方法可以做到这一点?答案是,我们可以将最后一个条目插入到最后一段的任意两个位置之间,包括开始和结尾,并且有比该条目更多的方法。换句话说,完成此迭代的方式数量与该迭代要完成的独特工作数量相匹配!

的意思是总功与O(choose(N+k, N))也是O(choose(N+k, k))成正比。

值得一提的是,从正态近似到二项式,如果为N = k,则证明它是O(2^(N+k)/sqrt(N+k)),其增长速度确实快于多项式。如果您需要更一般或更精确的近似值,可以对choose(N+k, N) = (N+k)! / ( N! k! )中的阶乘使用Stirling's approximation