最後更新日期 2024 / 01 / 01

C++ 常見 STL 教學

piar

簡介

pair 是一種可以儲存兩個元素的資料結構

用途

通常用來儲存二維座標或者是陣列的 index 與 value
而且常數較小
如果用 array / vector 替代有些題目真的會被卡 TLE

語法

// 宣告一個第一個欄位為 1 第二個欄位為 5 的 pair
// 在一些 c++ 版本較舊的環境下要使用 make_pair(1, 5)
pair<int, int> pos = {1, 5};

// 取得第一個欄位的值
cout << pos.first << endl;

// 取得第二個欄位的值
cout << pos.second << endl;

// 將 pos 的第一個欄位的 1 改成 2
pos.first = 2;

// 將 pos 的第二個欄位的 5 改成 4
pos.second = 4;

比較

在比較兩個 pair 時會先比第一個元素
如果第一個元素相同才會比第二個元素

vector

簡介

跟傳統陣列差不多
不過長度是可變的
會因為加入更多元素讓 vector 變得更長

用途

不用多說了吧
就是可以像陣列一樣儲存 n 個元素

語法

// 直接宣告 vector 的方式
vector<int> v1;

// 宣告長度為 n 的 vector
vector<int> v2(n);

// 宣告長度為 n 且每個元素都是 5 的 vector
vector<int> v3(n, 5);

// 宣告一個有元素 {1, 2, 3, 4} 的 vector
vector<int> v4 = {1, 2, 3, 4}

// 宣告一個跟其他 vector 一樣的 vector (複製)
vector<int> v5(v4);

// 加入元素在尾端
v1.push_back(7);

// 從尾端移除元素
v1.pop_back();

// 存取 vector 中的某一項
cout << v4[2] << endl;

// 取得大小
cout << v2.size() << endl;

比較

從第一個元素開始比較
如果相同就繼續往後比
直到第一個不同為止

queue

簡介

像是一個排隊的隊伍
可以從一端進入
從另一端離開
也就是先進去的會先離開

用途

大部分情況用來實作一些較複雜的演算法
比如 BFS、拓撲排序等等

語法

// 宣告一個 queue
queue<int> q;

// 將元素 5 推入 queue 後端
q.push(5);

// 取得 queue 前端的元素
cout << q.front() << endl;

// 取得 queue 後端的元素
cout << q.back() << endl;

// 將隊伍前端的元素彈出(移除)
q.pop();

// 檢查 queue 是否為空
if (q.empty()) {
    cout << "empty" << endl;
}

// 取得 queue 的大小
cout << q.size() << endl;

stack

簡介

類似於一疊盤子
最後放上去的盤子會最先被取走
而你不能從中間拿走盤子
也就是說後進去的會先出去

用途

stack 常用來會處理一些匹配類問題
或者是模擬遞迴
更進階一點還有單調堆疊之類的玩法

語法

// 宣告一個 stack
stack<int> stk;

// 將元素 3 推入 stack
stk.push(3);

// 從 stack 頂端取出元素
cout << stk.top() << endl;

// 將 stack 頂端的元素彈出(移除)
stk.pop();

// 檢查 stack 是否為空
if (stk.empty()) {
    cout << "empty" << endl;
}

// 取得 stack 的大小
cout << stk.size() << endl;

set

簡介

就是集合的意思
用來儲存不重複的元素
並會按照元素的大小自動排序

用途

主要用於快速插入和查找元素

語法

// 宣告一個 set
set<int> st;

// 插入元素
st.insert(5);
st.insert(3);
st.insert(7);

// 檢查 set 是否包含某元素
if (st.find(3) != st.end()) {
    cout << "set contains 3" << endl;
} else {
    cout << "set does not contain 3" << endl;
}

// 刪除元素
st.erase(5);

// 遍歷 set 中的元素
for (int e : st) {
    cout << e << " ";
}

// 取得 set 的大小
cout << st.size() << endl;

// 取得 set 的第一項
// 因為回傳的是 iterator 所以要加 *
cout << *st.begin() << endl;

// 取得 set 的最後一項
// 由於 back 是開區間所以要 -1
cout << *--st.end() << endl;

map

簡介

語法根陣列有點像
不過可以接受整數以外的型態來當作索引值

用途

有些時候需要使用負數、非常大的數字、字串等等來當索引值
map 就會是一個很方便的工具

語法

// 宣告一個以 string 為索引,int 為值的 map
map<string, int> mp;

// 把字串對應到數字
mp["one"] = 1;
mp["two"] = 2;
mp["three"] = 3;

// 輸出 one 的值
cout << mp["one"] << endl;

// 在 map 中刪除 one
mp.erase("one");

// 遍歷 map
for (auto [key, value] : mp) {
    cout << key << ", " << value << endl;
}

// 取得 map 的大小
cout << mp.size() << endl;

priority queue

簡介

又稱為 heap
可以支援快速地插入及查詢最大最小值

用途

很常使用在一些複雜的演算法內
比如最短路徑、最小生成樹等等

語法

// 宣告一個 priority queue
priority_queue<int> pq;

// 宣告一個 priority queue 並且頂部為最小值
priority_queue<int, vector<int>, greater<int>> pq;

// 插入元素
pq.push(3);
pq.push(1);
pq.push(5);

// 取得頂端的元素(最大值)
cout << pq.top() << endl;

// 移除頂端的元素
pq.pop();

// 檢查 priority queue 是否為空
if (pq.empty()) {
    cout << "empty" << endl;
}

// 取得 priority queue 的大小
cout << pq.size() << endl;

推薦文章

題解 CSES Restaurant Customers

給你 n 位客人的進入和離開餐廳的時間 輸出最多同時有幾位客人同時在餐廳- n le 2 times 10^5把每個人加入時間和離開的時間分別看成兩個時間點 並把所有時間點加入陣列後一起排序 然後用一個變數來維護目前餐廳人數 每次遇到加入就增加 反之遇到離開就減少 維護中遇到的最大值就是答案了 時間複雜度:Oncpp using namespace std; signed main { int n; cin n; vectorpii v; for int i = 0; i n; i++ { int s, t; cin s t; v.pushback{s, true}; v.pushback{t, false}; } sortv.begin, v.end; int cur = 0; int ans = 0; for auto e : v { if e.ss == true cur++; else cur--; ans = maxcur, ans; } cout ans endl;}

CSES

題解 CSES Sum of Divisors

定義 sigmax 為 x 的所有因數之和 給予一個 n 求 sum^n{k=1}sigmak 之值以 12 為例 先看一下這張圖列出了 1 sim 12 的所有因數可以發現每兩個數字就會出現一次 2 每三次數字就會出現一次 3 觀察後可知 對於一個數字 x 它的出現次數會是 lfloor frac{n}{x} rfloor 因為每 x 個數字就會出現一個 x 的倍數 用這個做法枚舉每個數字計算就可以得到一個 On 的算法 但這樣還不夠快到足以處理這題 10^{12} 的資料量如果我們把剛剛那張圖的呈現方式改一下 上面那一橫排代表因數 1 sim 12 下面那一行排代表該因數出現的次數可以發現這張圖內有幾串連續的因數出現次數相同 因為事實上在計算這個的過程中只會出現最多 2 sqrt n 個相異數字 證明上面那張圖每個紅色圈起來代表一塊 如果我們可以塊為單位來計算就可以把時間複雜度降到 Osqrt{n} 了想像一下 如果 n 除以 x 可以剛好整除的話 令 k = lfloor frac{n}{x} rfloor 則 lfloor frac{n}{k} rfloor 必定等於 k 那如果不是剛好整除的呢? lfloor frac{12}{5} rfloor = 2 ,quadlfloor frac{12}{2} rfloor = 6 再試試看 6 lfloor frac{12}{6} rfloor = 2 ,quadlfloor frac{12}{2} rfloor = 6 觀察後發現 這裡的 6 就是最大的 x 滿足 frac{n}{x} 為 2 於是這樣我們就可以找到最後一個連續出現次數相同的因數 最後只要把每次一塊的第一個數和最後一個數用梯形公式求總和乘上共同的出現次數就可以得到答案了不過這邊要注意的是 因為答案很大所以題目要我們對 10^9 + 7 取模 但梯形公式中又會用到除法 所以我們不能直接除 需要先求出模反元素.modulo-inverse再乘進去才行cppusing namespace std;const int mod = 1e9 + 7;const int inv = 500000004; signed main { int n; cin n; int cur = 1; int ans = 0; while cur = n { int cnt = n cur; int last = n cnt; int sum = last + cur % mod last - cur + 1 % mod % mod inv % mod; ans += sum % mod cnt % mod % mod; cur = last + 1; } cout ans % mod endl;}

CSES

Dcard 實習計畫 2024

這次去 SITCON 玩大地遊戲的時候,剛好在 Dcard 攤位看到正在招募 2024 暑期實習計畫的實習生,於是我就過去了跟他們聊了一下,沒想到他們竟然說高中生只要有時間也可以來報名看看,身為自學生的我怎麼能錯過這樣的機會呢!按照實習計畫的說明,在投遞履歷的同時,還需要附上「作業」,而這次的作業內容大概就是要建立一個可登入、發文然後串 Github API 的 blog 網頁。alt text我在開始製作這個作業時,其實對於 React 的了解其實幾乎趨近於零,沒有抱持的太大的期待就開始做下去了,想說就透過這個作業邊寫邊學 React 和 Next.js。過程中其實遇到不少困難,起初就是 useEffect 用得太差,導致出現一堆問題,網路上查了許多資料都沒辦法完美的解決我遇到的困難,直到發現了 A Complete Guide to useEffect 這篇文章,對英文不是很好的我來說,這超長的文章大概也花了我兩天的時間才讀完。幸運的是,這篇文章寫得非常詳細而且解決了我遇到的問題,感覺我就是基礎很不扎實吧。alt text除了 useEffect 以外,還遇到另外一個更棘手的就是 Next.js 的快取問題,每當我發布 blog 文章之後,無論怎麼重新載入我的文章都不會顯示出來。翻了 Next.js 的文件才發現快取系統怎麼這麼複雜,總之後來又花了一些時間把 Next.js 的文件都好好讀一一讀,最終稍微解決了這個問題,但解法似乎不是非常優雅。繳交期限最後一週,我參考了之前 某個被錄取的實習生的作業 寫好了 README.md 文件就交上去了。如果有興趣的話,你可以在 這裏 看到我當時的作業,總共 320 個 commits,我花了整整一個月的時間在上面。作業繳交上去幾天後,很順利的收到了面試通知,那時候看到這個超開心!alt text距離面試時間,還有兩週多,首先我上網查了一些資訊,看看之前的 Dcard 面試到底都做了什麼。因為某篇文章說建議去讀 React 底層的東西,於是我就找了 React 技術揭密 這本電子書來讀,裡面真的提到了非常多很底層的東西,像是什麼 fiber node 之類的,不過最後還是看不太懂qwq,因此放棄了這本書。或許對我來說 React 底層太難了,但我至少可以繼續增進我對 React 的了解,根據前面 Next.js 的學習經驗,我決定要把 React 的文件全部讀過一遍!還在 Obsidian 整理了蠻多的筆記,感覺有機會可以公開出來。alt text大約一週的時間,我把 React 讀得差不多了,過程中其實發現了不少作業中可以優化的地方也改上去了。然後又再回去看一下之前面試的考古題,發現我對 Javascript 的了解似乎也不夠深,尤其時原型練之類的東西。最後根據 某 Javascript 大師 的推薦,讀了 這個系列 的文章,真的挺優質的,很多其他地方看不到的內容裡面都有。這部分我比較多的時間可能都還是在研究原型鏈。alt text接下來也花了一些時間學 git 更進階的指令,這個網站 真的挺有意思的,到後面感覺很像在玩解謎遊戲。alt textgit 的部分也整理了一些筆記,不過沒 React 那麼多就是了。alt text面試前兩三天,繼續查了一下考古題,看看 HR 面試的關卡會做什麼,但好像也沒查到什麼太有用的資訊。結果反而有點不知道要做什麼,於是就去處理了一些雜事,把之前 side project 想加的東西加上去、把還沒發佈的 chrome extension 給 publish 上去有的沒的。大概提前兩個多小時左右就先到了現場,看一下面試地點大概在什麼地方,然後去吃個午餐休息一下,本來想再複習一下結果好像來不及了。進公司之後,他們先跟我介紹了一下 Dcard 的歷史,然後參觀一下工作環境(看起來真的很舒服)。接著迎來的第一關就是 HR 面試。其實氛圍還算滿輕鬆的,不過我還是有點緊張。剛開始有跟他們聊了一下關於我現在自學生的身份和接下來的升學打算,後來還有提到問我是如何學習一項新的技術、以及程式學習的歷程,然後問我短中長期規劃之類的。因為我個人網站上面寫了很多比賽的經歷,他們也根據這個詢問了我一些相關問題,比如為什麼想參加這些比賽、跟隊友賽中的策略怎麼樣等等,在小組合作過程當中的協作模式、有沒有遇過衝突及如何化解有的沒的。這邊其實我覺得很多問題我都沒有回答得很好,或者是思考停頓了太久。alt text下一個階段是 Frontend Team 的面試,他們問了很多關於 React 的問題,包含 useMemo、useCallback、SSR、CSR、await async 跟 promise 差在哪、SSG、server component 跟 client component 的差別等等。比較令我印象深刻的是有一題他們問 server component 跟 server side rendering SSR 差在哪裡,第一瞬間幾乎沒什麼靈感,想說不就是 server component 才會 server rendering 這樣嗎,思考一小段時間之後突然有一點想法回想起來之前在看 Next build 結果的時候就連 client component 也被標示成 SSR,於是我就有點免強的回答說:「client component 也會用到 SSR... 對吧?」,似乎應該是正確答案,不過感覺回答的很不完整。另外一個也讓我思考了蠻久的問題就是「Suspense 在 server component 的運作原理是什麼?它是如何做到載入好後把 fallback 替換成取得到的資料的?」,這題我就真的幾乎完全沒頭緒了,雖然大概給了一點零散地回答剛好提到了 streaming 這個詞,他們就說算是有擦到一點邊,對於這個沒回答出來的問題他們也好心的跟我解釋了 Suspense 到底是怎麼是怎麼運作的。alt text剩下一些沒有回答的很好的問題還有,「有沒有自調整過 webpack 的 config」,我回答沒有,大多數情況下都是用 framework 的 default config。「web vitals 的評分項目」,雖然用過,但我幾乎忘光了。作業的部分他們也提到了我的 blog 頁面的 error handling 沒有做得很好,某個 promise 的 .catch 後面沒判斷就直接接了 notFound。然後 blog 頁面的 cache miss 掉以及我用 Map 實作了奇怪的小 cache 也被抓到,快取的部分真的被問得挺慘的ww還有因為之前的專案都是 Vue 寫的,所以他們也稍微問了一些關於 Vue 的問題,比如說你覺得 Vue 跟 React 差在哪、更喜歡哪個之類的,但其實我現在對 Vue 的了解度應該比 React 還低,這部分也挺慘的。面試最後我問他們我還有什麼地方是可以加強的,他們第一句話就是說我非常優秀,三年能學到這樣已經比很多 Junior 強了(這真的讓我很感動),鼓勵的部分結束後,他們給我的建議是應該再多了解 React、Next 的底層在做什麼,可以常常觀察 Devtools 裡面的 Network Tab 到底傳了什麼東西過來。面試結束後的下一週,他們就寄了審核結果的資訊到我的信箱。alt text打開來看到我沒有錄取,其實當初還蠻失望的,不過仔細這樣回過頭來看看這段時間發生的事,沒有錄取好像也挺合情合理的。至少在這個過程當中我真的學習到了非常多東西,了解到自己許多不足的地方,認識了所謂的「面試」到底是什麼,甚至還讓我從 0 學會了 React 跟 Next XD,再次感謝 Dcard 願意給我這次嘗試的機會 如果沒有 Dcard,我很難想像我可以在兩個月之內成長這麼多!統整一下這段時間發生的事情,首先我認為最明顯的缺點應該就是我對 React 和 Next 技術及經驗還不夠充足,尤其是關於偏底層的部分。再來就是技術面試以外的部分我幾乎不知道怎麼準備,感覺 HR 那關我幾乎都是在亂答,像是他們問說有沒有在合作過程當中遇到衝突然後怎麼處理,我回答幾乎沒有,可能藉由這個答案被判斷成我沒什麼合作經驗(雖然這確實),還有短中長期計畫那題也是想了蠻久的。無論如何,接下來這一年我希望可以:- 寫更多前端技術文章- 更深入了解 React Next 底層技術- 學習 webpack- 學習 redux- 累積更多合作開發的經驗希望明年就可以錄取 Dcard!!!

Journal