# 0-14 常用工具/函式 講義不是我寫的,網址在此 https://emanlaicepsa.github.io/2020/10/21/0-index/ 我只是將自己寫的練習題程式碼記錄下來。 最後更新日期:2024年10月6日 ## [TOJ: 55 / Number](https://toj.tfcis.org/oj/pro/55/) ### Python 程式碼 用 collections 函式庫的 Counter 計數,但是第3筆測資記憶體爆掉。 ```python= from collections import Counter n = int(input()) songs = list(map(int, input().split())) cnt = Counter(songs) # 計數器,計算各個編號歌曲的數量 m = int(input()) for _ in range(m): print(cnt[int(input())]) ``` 改用 bisect 函式庫 bisect_right 及 bisect_left,數量即為兩者回傳值的差,但是第3筆測資記憶體爆掉。 ```python= from bisect import bisect_left, bisect_right n = int(input()) songs = sorted(list(map(int, input().split()))) m = int(input()) for _ in range(m): i = int(input()) print(bisect_right(songs, i) - bisect_left(songs, i)) ``` ### C++ 程式碼 用 map 字典計數,執行時間最久約為 1697 ms,使用記憶體最多約為 48944 kB,通過測試。 ```cpp= #include <iostream> #include <map> using namespace std; int main() { ios::sync_with_stdio(0),cin.tie(0); int N, M, song; cin >> N; map<int, int> songs; for(int i=0; i<N; i++) { cin >> song; songs[song]++; } cin >> M; for(int i=0; i<M; i++) { cin >> song; cout << songs[song] << "\n"; } return 0; } ``` 用 unordered_map 字典計數會更快,執行時間最久約為 784 ms,使用記憶體最多約為 40604 kB,通過測試。 ```cpp= #include <iostream> #include <unordered_map> using namespace std; int main() { ios::sync_with_stdio(0),cin.tie(0); int N, M, song; cin >> N; unordered_map<int, int> songs; for(int i=0; i<N; i++) { cin >> song; songs[song]++; } cin >> M; for(int i=0; i<M; i++) { cin >> song; cout << songs[song] << "\n"; } return 0; } ``` 改用 algorithm 函式庫 upper_bound 及 lower_bound,數量即為兩者回傳值的差,執行時間最久約為 898 ms,使用記憶體最多約為 6164 kB,通過測試。 ```cpp= #include <iostream> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(0),cin.tie(0); int N; cin >> N; int songs[N]; for(int i=0; i<N; i++) cin >> songs[i]; sort(songs, songs+N); int M; cin >> M; for(int i=0, x; i<M; i++) { cin >> x; cout << upper_bound(songs, songs+N, x) - lower_bound(songs, songs+N, x) << "\n"; } return 0; } ``` ## [TOJ: 47 / PB magic spell](https://toj.tfcis.org/oj/pro/47/) ### Python 程式碼 使用二分搜尋法,會遇到 RuntimeError。 ```python= from bisect import bisect_left n = int(input()) xs = sorted(list(map(int, input().split()))) t = int(input()) for _ in range(t): k = int(input()) idx = bisect_left(xs, k) if idx == n: # k 大於 xs 中的最大值 print(f"{xs[-1]:d} no") # 只有小於 k 的值,其中的最大值是最後一項 elif xs[idx] == k: # 如果 xs[idx] 等於 k print(k) # 印出 k elif idx == 0: # k 小於 xs 中的最小值 print(f"no {xs[0]:d}") # 只有大於 k 的值,其中的最小值是第0項 else: # k 介於 xs 的數值之間 print(f"{xs[idx-1]:d} {xs[idx]:d}") ``` 先判斷 k 是否小於最小值或大於最大值,如果不是再用二分搜尋法,但還是會遇到 RuntimeError。 ```python= from bisect import bisect_left n = int(input()) xs = sorted(list(map(int, input().split()))) t = int(input()) imin, imax = xs[0], xs[-1] for _ in range(t): k = int(input()) if k < imin: # k 小於 xs 中的最小值 print(f"no {imin:d}") # 只有大於 k 的值,其中的最小值是 imin elif k > imax: # k 大於 xs 中的最大值 print(f"{imax:d} no") # 只有小於 k 的值,其中的最大值是 imax else: # k 介於 xs 的數值之間 idx = bisect_left(xs, k) # 二分搜尋法,找出於 xs 插入 k 的索引值 if xs[idx] == k: # 如果 xs[idx] 等於 k print(k) # 印出 k else: # 印出小於 k 的最大值、大於 k 的最小值 print(f"{xs[idx-1]:d} {xs[idx]:d}") ``` ### C++ 程式碼 使用二分搜尋法,超時。 ```cpp= #include <iostream> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; int xs[n]; for(int i=0; i<n; i++) cin >> xs[i]; sort(xs, xs+n); int t; cin >> t; for(int i=0; i<t; i++) { int k; cin >> k; int idx = lower_bound(xs, xs+n, k) - xs; if (idx == n) { // k 大於 xs 中的最大值 cout << xs[n-1] << " no\n"; // 只有小於 k 的值,其中的最大值是最後一項 } else if (xs[idx] == k) { // 如果 xs[idx] 等於 k cout << k << "\n"; // 印出 k } else if (idx == 0) { // k 小於 xs 中的最小值 cout << "no " << xs[0] << "\n"; // 只有大於 k 的值,其中的最小值是第0項 } else { // k 介於 xs 的數值之間 cout << xs[idx-1] << " " << xs[idx] << "\n"; } } return 0; } ``` 先判斷 k 是否小於最小值或大於最大值,如果不是再用二分搜尋法,執行時間最久約為 158 ms,使用記憶體最多約為 4372 kB,通過測試。 ```cpp= #include <iostream> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(0); cin.tie(0); int n; cin >> n; int xs[n]; for(int i=0; i<n; i++) cin >> xs[i]; sort(xs, xs+n); int imin = xs[0], imax = xs[n-1]; int t; cin >> t; for(int i=0; i<t; i++) { int k; cin >> k; if (k < imin) { // k 小於 xs 中的最小值 cout << "no " << imin << "\n"; // 只有大於 k 的值,其中的最小值是 imin } else if (k > imax) { // k 大於 xs 中的最大值 cout << imax << " no\n"; // 只有小於 k 的值,其中的最大值是 imax } else { int idx = lower_bound(xs, xs+n, k) - xs; if (xs[idx] == k) { // 如果 xs[idx] 等於 k cout << k << "\n"; // 印出 k } else { // k 介於 xs 的數值之間 cout << xs[idx-1] << " " << xs[idx] << "\n"; } } } return 0; } ``` ------ ###### tags:`演算法`、`APCS`、`Python`、`C++`