甚麼是時間複雜度?
時間複雜度對我(你)來說很重要嗎?
怎麼估複雜度?
雖然是遠距上課,但還是希望大家能有多一點互動
有想法就可以提出來
課程內容的難易度未必適合所有人
有問題就問
覺得太簡單不用急,後面的講師一定可以滿足你
雖然這堂課可能偏理論,但並非那麼嚴謹
一個描述該演算法(或程式)執行時間的函式
通常假設各種基本操作都花一單位時間
加、減、乘、除、取模
賦值
條件判斷
存取變數
…...
\(F(N) = N^2+2N+3\)
cin >> N;
i = 0;//1
j = 0;//1
while(i < N)//N+1
{
while(j < i)//1+2+3+..+N=(N+1)N/2
{
j++;//1+2+3+..+(N-1)=(N-1)N/2
}
i++;//N
}
\(f(x) = O(g(x))\) 代表存在\(M,x_0 > 0\),使得所有\(x \geq x_0\)都有\(|f(x)|\leq M|g(x)|\)
也就是說,當\(x\)很大的時候,存在常數\(M\),使得\(M|g(x)|\)一定會大於等於\(f(x)\)
其實也就表示,\(g(x)\)是\(f(x)\)的某種上界
看例子!
\(f(x)\)
\(g(x)\)
\(f(x) = O(g(x))\)?
\(x\)
\(100x\)
Yes
\(x\)
\(100x\)
Yes
\(x^3\)
\(x^2\)
No
\(x^2\)
\(\frac{x^2\log(x)}{10000}\)
Yes
Yes
\(x-1000\sqrt{x}-100\)
\(x\)
可以看出,只要有了big-O符號,我們就可以無視低次項跟常數,更方便地表示複雜度
因此,在剛剛的例子中,原本複雜度是
\(F(N)=N^2+N+4\),現在也可以用\(O(N^2)\)來表示該程式的時間複雜度
雖然也可以用\(O(N^3)\)來表示,但我們追求的是複雜度越小越好!
這樣估複雜度就不用那麼麻煩了!
\(O(N^3)\)
cin >> N;
i = 0;
j = 0;
while(i < N*N+N-2)
{
while(j < N*3-10)
{
j++;
}
i++;
}
\(O(N^2\sqrt{N})\)
cin >> N;
i = 0;
j = 0;
while(i < N*N+N-2)
{
while(j*j < N)
{
j++;
}
i++;
}
即使你的程式是正確的,如果他的執行時間超過了題目的限制,你會得到一個 而無法得到分數
一般的judge一秒可以跑\(10^8\)筆運算左右,所以想要知道自己的程式會跑幾秒,就把題目的範圍限制代入所估的複雜度中,最後再除以\(10^8\)。然後再跟題目的限制秒數比比看就可以知道會不會TLE了
注意我們要估的通常是最糟的情形
給定一個單字,請你找出其中"最長的"連續的一段,使得那段正著唸反著唸都一樣。(單字長度\(L \leq 5000\))
範例輸入:
abcbbd
範例輸出:
bcb
枚舉所有的「連續的一段」,再把那一段掃過一遍就好囉!
abac
abac
abac
abac
abac
abac
abac
abac
abac
abac
因為長度為\(1\)的區間有\(L\)個,\(2\)的區間有\(L-1\)個,...,\(L\)的區間有\(1\)個,所以複雜度是\(1\times L+2\times (L-1)+...+L\times 1=\frac{L^3+3L^2-4L}{6}\)
複雜度是:
枚舉連續的一段 \(O(L^2)\)
然後再把那段掃一遍 最糟\(O(L)\)
所以就是\(O(L^3)\)囉!
跑100秒都跑不完QQ
枚舉所有的「中間點」,然後看可以往外擴張多少!
枚舉所有的「中間點」,然後看可以往外擴張多少!
a b c b b d
長度:3
枚舉所有的「中間點」,然後看可以往外擴張多少!
a b c b b d
長度:2
複雜度是:
枚舉中間點(包含中間字母語中間空隙) \(O(L)\)
然後看可以往外擴張多少 最糟\(O(L)\)
所以就是\(O(L^2)\)囉!
\(5000^2 = 2.5 \times 10^7\),理論上一秒內可以跑完!
回文好玩好文回(6)
10 min
除了判斷自己的演算法可不可以拿到想要的分數之外,因為比較難的題目通常都會把限制的範圍出的盡量大,所以看到範圍後也可以得到一些關於作法複雜度的線索
給你一個正整數\(Q\),接下來有\(Q\)筆詢問,每次詢問你一個整數\(N\)是不是質數。
範例輸入:
\(3\)
\(1\)
\(2\)
\(3\)
範例輸出:
No
Yes
Yes
給你一個正整數\(Q\),接下來有\(Q\)筆詢問,每次詢問你一個整數\(N\)是不是質數。
範圍:\(Q\leq 100\),\(N\leq 10^{10}\)
給你一個正整數\(Q\),接下來有\(Q\)筆詢問,每次詢問你一個整數\(N\)是不是質數。
範圍:\(Q\leq 10^6\),\(N\leq 10^6\)
說到最直接判斷質數的方法
試除法?
質數判斷(7)
9 min
說到找出比\(K\)小的質數的方法
篩法?
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
這樣做的複雜度是\(\frac{K}{2}+\frac{K}{3}+\frac{K}{5}...\)
有點難估所以抓個上界:
\(\frac{K}{2}+\frac{K}{3}+\frac{K}{5}...\leq K(1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{K})\)
質數判斷2(11)
9 min
\(Q\leq 100,N\leq 10^{10}\)
\(Q\leq 10^6,N\leq 10^6\)
\(O(Q\sqrt{N})\)
\(O(Klog(K)+Q)\)
AC
AC
TLE
TLE
範圍
做法複雜度
\(N\leq 10\)
\(O(4^N),O(N^7),O(N!),...\)
\(N\leq 20\)
\(O(N\times2^N),O(N^6),...\)
\(N\leq 50\)~ \(100\)
\(O(N^4)\)
\(N\leq 200\)
\(O(N^3log(N))\)
\(N\leq 500\)
\(O(N^3)\)
\(N\leq 2000\)
\(O(N^2log(N))\)
範圍
作法複雜度
\(N\leq 5000\)
\(O(N^2)\)
\(N\leq 5\times 10^4\)
\(O(N\sqrt{N})\)
\(N\leq 10^5\)
\(O(N\sqrt{N}),O(Nlog^2(N)),O(Nlog(N))\)
\(N\leq 10^6\)
\(O(Nlog(N)),O(N)\)
\(N\leq 10^7\)
\(O(N)\)
\(N\leq 10^{12}\)
\(O(\sqrt{N})\)
\(N\leq 10^{18}\)
\(O(log(N)),O(log^2(N)),...\)
其實大家都會了?
根據之前的例子,基本上就是看每一層迴圈最多跑多少次,然後全部乘起來?
但是......
給你一個單字,你要從中找到其中連續的一段,使得該段是包含全部的字母中最短的(很多個的話請輸出最先出現的,不存在請輸出"QQ")
範例輸入:
aabbabcdefghijklmnoqrstuvwxyz
範例輸出:
abcdefghijklmnoqrstuvwxyz
a b c b a
a | b | c |
---|---|---|
\(L\)
a b c b a
a | b | c |
---|---|---|
1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 1 | 1 |
\(L\)
長度:3
a b c b a
a | b | c |
---|---|---|
\(L\)
a b c b a
a | b | c |
---|---|---|
1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
2 | 1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 2 | 1 |
\(L\)
長度:4
a b c b a
a | b | c |
---|---|---|
\(L\)
a b c b a
a | b | c |
---|---|---|
1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 1 | 1 |
\(L\)
長度:3
a b c b a
a | b | c |
---|---|---|
1 | 1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
2 | 1 |
\(L\)
a b c b a
a | b | c |
---|---|---|
1 | 2 | 1 |
\(L\)
長度:4
for(L = 1;L <= N;L++)
{
for(R = L;R <= N;R++)
{
//do something
if(something happens)
{
ans = min(ans,R-L+1);
break;
}
}
}
int R = 1;
for(L = 1;L <= N;L++)
{
while(R <= N)
{
//do something
if(something happens)
{
ans = min(ans,R-L+1);
//do something
break;
}
R++;
}
}
電皇的小寫英文字母(5)
15 min
int f(int n)
{
if(n == 1) return 1;
return n*f(n-1);
}
\(f(n)\to f(n-1) \to ... \to f(1)\)
每個函式本身都\(O(1)\)
總共\(O(n)\)!
int Pow(int a,int b)
{
if(n == 0) return 1;
int t = Pow(a,b/2);
if(b & 2 == 1) return t*t*a;
else return t*t;
}
每個函式本身都\(O(1)\),共有\(O(log(b))\)次函式被呼叫
總共\(O(log(b))\)!
void f(int n)
{
if(n <= 1) return 1;
//Do some O(n) things
f(n/2);
f(n/2);
}
\(f(n)\)
\(f(\left \lfloor \frac{n}{2} \right \rfloor)\times 2\)
\(f(\left \lfloor \frac{n}{4} \right \rfloor)\times 4\)
\(\cdots\)
\(\cdots\)
\(\cdots\)
\(f(1)\times n\)
每層都是跑\(O(n)\)
總共有\(O(log(n))\)
總複雜度\(O(nlog(n))\)!
上課例題:
回家練習: