Time Complexity
Arvin Liu @ Sprout 2021
階段考TLE了啦 QQ...
階段考TLE了啦 QQ...
可不可以預判TLE呢?
要是能重來,我就不會浪費時間寫這題了>_<
預測時間
預測時間? 算算看指令數有多少
int n, sum = 0;
cin >> n;
for (int i=1; i<=n; i+=1)
sum += i;
cout << sum;
宣告
3次
輸入輸出
2次
判斷 i <= n
+=
n, i, sum
cin >> n;
cin << sum;
n+1次
因為 i 會
從 1 跑到 n+1
2n次
因為 i+n次
sum也+n次
指令數量 : 3n + 6 次
預測時間? 算算看指令數有多少
int n;
cin >> n;
for(int i=1; i<=n; i++){
for(int j=0; j<n-i; j++) cout << " ";
for(int j=0; j<i; j++) cout << i;
cout << " ";
for(int j=0; j<i; j++) cout << i;
cout << "\n";
}
指令數量 : 次
我也不知道
去算那種枝微末節的指令數真的有用嗎?
誰算得出來==
當然,神如Jason就算得出來。
所以我們需要估計時間
指令數
大概是...
所以其實我們只要看最大的那一項就差不多了!
重看一次
int n;
cin >> n;
for(int i=1; i<=n; i++){
for(int j=0; j<n-i; j++) cout << " ";
for(int j=0; j<i; j++) cout << i;
cout << " ";
for(int j=0; j<i; j++) cout << i;
cout << "\n";
}
有沒有一個符號
表達估計指令數呢?
O
英文字母的第15個字
大O (big-Oh) 的定義
看不懂? 沒關係。
就是取成長最快的項 再把係數拿掉就好了。
這裡的O,我們就稱之為複雜度,表示程式要跑多少次指令。
= 取成長最快的項 再把係數拿掉就好了。
指令數 | 時間複雜度 |
---|---|
大O (big-Oh) 的定義
小小補充
小小補充-2
看起來好像很厲害的成長速率圖
所以那個TLE呢?
Got TLE?
Time Limit Exceeded
想一個解法
最差時間複雜度
計算code的指令數
TLE or
... WA?
估算
複雜度
代入測資
總而言之就是帶進去看有1秒沒有超過 就對了!
你還沒寫code啊,小老弟
比較常看到的複雜度 - 範圍
時間複雜度 | n 的範圍 |
---|---|
題外話:你怎麼念O(1)?
題外話:你怎麼念O(1)?
有if怎麼辦?
指令數可能每次都不一樣...
if (rand() % 2 == 0) {
一個歐恩平方的函式();
} else {
一個歐恩的函式();
}
公O小?
很多的複雜度
最佳複雜度
最差複雜度
平均複雜度
什麼意思?
就...跑最快的時候啊
就...跑最慢的時候啊
就...平均的時候啊
期望值的次數
很多的複雜度
if (rand() % 2 == 0) {
一個歐恩平方的函式();
} else {
一個歐恩的函式();
}
哪種複雜度? | 複雜度多少? |
---|---|
最佳複雜度 | |
最差複雜度 | |
平均複雜度 |
絕對不是 ,是
偷渡一個排序 - Bogo Sort
排序是什麼? 就是把數字由小到大排。
什麼是Bogo Sort?
猴子表示: 要排序乾我?
Bogo Sort:
叫一隻猴子把
寫有數字的卡牌往空中一撒,
然後撿起來看順序對不對。
沒有? 再撒一次!
所以這個算法又稱猴子排序。
Bogo Sort 的複雜度?
哪種複雜度? | 複雜度多少? |
---|---|
最佳複雜度 | |
最差複雜度 | |
平均複雜度 |
is_sorted = False
while not is_sorted:
shuffle(ary) # O(n)
if ary.is_sort(): # O(n)
is_sorted = True # O(1)
shuffle:
洗牌/打亂順序
因為只有
機率排對。
總而言之...
我們平常講O都是講最差複雜度,小心誤用。
O小好嗎?
一個奇怪的比較
指令數 | 時間複雜度 |
---|---|
平常情況下
10000000000 n 比 n*(n-1)/2 還要慢,
但是時間複雜度卻比較低。
O只是重要參考,但不代表真實情況(?)
Examples
一個你看過的例子
- 假設說一開始的n個數字:
- 那麼接下來詢問3次。
- 詢問 2 -> 回答不存在。
- 詢問 3 -> 回答存在。
- 詢問 7 -> 回答存在。
一個你看過的例子
一個最簡單但很慢解法:
用大小為n的陣列紀錄,每次詢問就用for看y在不在這個陣列裡面。
步驟 | 輸入到陣列 | 每次詢問 | 總共 |
---|---|---|---|
最差複雜度 | O(N) | O(N) | O(QN) |
一個你看過的例子
一個有趣,很快的解法:
輸入x時讓陣列A[x] = true,
判斷時用A[y]決定有沒有出現過。
索引值 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
A裡面的值 | T | F | T | F | F | F | T | T | F |
步驟 | 清空A陣列 | 設定A陣列 | 每次詢問 | 總共 |
---|---|---|---|---|
最差複雜度 | O(M) | O(N) | O(1) | O(M+N+Q) |
一個你看過的例子
一個最簡單但很慢解法:
用大小為n的陣列紀錄,每次詢問就用for看y在不在這個陣列裡面。
一個有趣,很快的解法:
輸入x時讓陣列A[x] = true,
判斷時用A[y]決定有沒有出現過。
最差時間複雜度
你所想的算法
結束啦!
騙你的(?)
還有喔?
步驟 | 排序 | ||
---|---|---|---|
最差複雜度 | O(NlogN) |
一個有趣,很快,不用管M的解法:
用大小為n的陣列排序,
再來用二分搜尋法判斷有沒有存在。
每次詢問 | 總共 | ||
---|---|---|---|
O(logN) | O((N+Q)logN) |
排序後的值 | 1 | 1 | 3 | 3 | 7 | 8 |
---|
小小整理
預處理 | 預處理時間複雜度 | 詢問 | 單次詢問時間複雜度 | 總時間複雜度 |
---|---|---|---|---|
直接存起來 | O(N) | 一個一個比對 | O(N) | O(QN) |
開一個陣列紀錄存過誰 | O(N+M) | 直接看紀錄陣列就好了 | O(1) | O(N+M+Q) |
存起來後排序 | O(NlogN) | 二分搜尋法 | O(logN) | O((N+Q)logN) |
你還想的到其他算法嗎?
Time Complexity
By Arvin Liu
Time Complexity
- 1,149