1. 程式人生 > 實用技巧 >三重迴圈演算法複雜度及探究

三重迴圈演算法複雜度及探究

三重迴圈演算法複雜度及探究

原題

求如下一個三重迴圈程式的演算法複雜度

for(i=1;i<=n;i++)
    for(j=1;j<=i;j++)
        for(k=1;k<=j;k++)
            m++;

二重迴圈

我們先來看一下一個標準的二重迴圈程式的複雜度是如何求的

for(int i=1;i<=n;i++)
    for(int j=1;j<=i;j++)
        m++;

這個演算法與氣泡排序的複雜度一樣是\(O(n^2)\)
計算過程如下:

\[\sum_{j=1}^{i}\sum_{i=1}^{n}1=\sum_{j=1}^{i}(1+1+...+1)=\sum_{j=1}^{n}j=1+2+3+...+n=\frac{n*(n+1)}{2} \]

三重迴圈

重新回到題目,可以得出以下計算步驟:

\[\sum_{k=1}^{j}\sum_{j=1}^{i}\sum_{i=1}^{n}1=\sum_{k=1}^{n}(\frac{k*(k+1)}{2})=\frac{1}{2}[\sum_{k=1}^{n}(k^2)+\sum_{k=1}^{n}k] \]

此時需要用到另外一個求和公式:\(S(n)=1+2^2+...+n^2=\frac{n*(n+1)*(2n+1)}{6}\)

推導步驟如下:

\[\begin{aligned} n^3-(n-1)^3&=3n^2-3n+1 \\ (n-1)^3-(n-2)^3&=3n^2-9n+7=3(n-1)^2-3(n-1)+1\\ &...\\ 2^3-1^3&=7=3*2^2-3*2+1\\ \end{aligned} \]

將上述式子相加,即:

\[\begin{aligned} \sum_{i=1}^{n}[i^3-(i-1)^3]&=n^3-1=3[n^2+(n-1)^2+...2^2]-3(n+n-1+...+2)+n-1\\ n^3&=3[n^2+(n-1)^2+...1^2]-3(n+n-1+...+1)+n\\ &=3S(n)-3\frac{n*(n+1)}{2}+n\\ S(n)&=[n^3-n+3\frac{n(n+1)}{2}]/3=\frac{n(n+1)(2n+1)}{6} \end{aligned} \]

則原式可得:

\[\frac{1}{2}[\sum_{k=1}^{n}(k^2)+\sum_{k=1}^{n}k]=\frac{S(n)+\frac{n(n+1)}{2}}{2}=\frac{n(n+1)(n+2)}{6} \]

編寫程式驗證,完全吻合結果:

#include<bits/stdc++.h>
#define ll long long
#define ld long double
using namespace std;
void f1(int n){
    ll cnt=0;
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=i;j++)
            for(ll k=1;k<=j;k++)
                cnt++;

    cout<<cnt<<" ";
    ll res=(ll)n*(n+1)*(n+2)/6;//公式法
    cout<<res<<" ";
    cout<<((ld)1.0*cnt/res?"true":"false")<<endl;
}
int main()
{
    for(int i=1;i<=100;i++)
        f1(i);
    return 0;
}

進一步探究

  1. 若修改\(k\)的範圍為\([1 - mj]\),則易知複雜度應為原式乘以\(m\)
  2. 若修改\(i\)的範圍為\(mn\),則易知複雜度為原式用\(mn\)帶入
  3. 若修改\(j\)的範圍為\([1-mi]\),則複雜度為原式\(*(2^2)^{log_{x}{m}}+C\),使用極限計算可得

    \[ans=\frac{n(n+1)((2^2)^{log_{2}{m}})*n+2+C)}{6} \quad C為常數 \]