三重迴圈演算法複雜度及探究
三重迴圈演算法複雜度及探究
原題
求如下一個三重迴圈程式的演算法複雜度
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;
}
進一步探究
- 若修改\(k\)的範圍為\([1 - mj]\),則易知複雜度應為原式乘以\(m\)
- 若修改\(i\)的範圍為\(mn\),則易知複雜度為原式用\(mn\)帶入
- 若修改\(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為常數 \]