-
Notifications
You must be signed in to change notification settings - Fork 0
Mastering LeetCode (C ): A Practical Roadmap
A focused plan to practice efficiently, write clean C++ solutions, and retain patterns. Designed to fit the
leetcodeExamplesrepo workflow (CMake + GoogleTest).
Jump to:
- Weekly Cadence
- Pattern Toolkit (What to Look For)
- C++ Mini-Templates (Drop-ins)
- Solve Framework (Use Every Time)
- Using This Repo Effectively
- Suggested Problem Sequencing
- Interview Timing (45-min)
- C++ Hygiene
- Tracking & Spaced Repetition
Daily (~75–90 min)
- Warm-up (10 min): Re-implement a previously solved problem from memory (core idea only).
-
New problem (45–50 min):
- 0–5: restate, identify pattern, choose DS.
- 5–25: code a first pass.
- 25–35: test edge cases, prove correctness, check complexity.
- 35–50: if stuck → peek a hint → finish; then re-implement once without looking.
- Notes (5 min): one-liner idea + traps.
- Spaced review (10–20 min): re-do items scheduled for D+1, D+7, D+30.
Weekly (1 session): Simulate a 45-min interview (2 mediums or 1 hard). Conduct a brief retrospective (pattern signal, bottlenecks, misses).
Arrays / Strings
- Sliding window (variable): “longest/shortest subarray with property”, “at most K distinct”.
- Two pointers: sorted arrays, partition/remove, palindrome checks.
- Prefix sum + hashmap: subarray sum = K, balanced counts, anagrams.
Stacks
- Monotonic stack: next greater/smaller element, “first left/right …”.
Intervals
- Sort by start/end; merging; maximum non-overlapping; rooms needed → sweep/heap.
Binary Search
- On index or answer with a monotone predicate
ok(x).
Linked Lists
- Fast/slow pointers; reverse; cycle; kth from end; merge k lists (heap).
Trees
- DFS (pre/in/post), BFS by level, recursion tricks, LCA, serialize/deserialize.
Graphs
- BFS/DFS; topological sort (Kahn/DFS); Union-Find; Dijkstra/0-1 BFS.
DP
- 1D: house robber, coin change, LIS.
-
Grid: paths, edit distance;
dp[i][j]from neighbors. - Subsequence: take/skip, knapsack.
- Interval DP: matrix chain, burst balloons.
Backtracking
- Subsets/Permutations/Combinations/Parentheses:
choose → recurse → unchoose.
The repo’s
leetcode.hppalready includes a portablepch.hpp(no<bits/stdc++.h>needed).
Sliding window (variable)
int best = 0; unordered_map<char,int> cnt;
for (int L=0,R=0; R<(int)s.size(); ++R) {
cnt[s[R]]++;
while (/* invalid */) { if(--cnt[s[L]]==0) cnt.erase(s[L]); ++L; }
best = max(best, R-L+1);
}Two pointers (sorted array)
int i=0,j=n-1;
while(i<j){
long long sum = a[i] + a[j];
if(sum == T) return pair{i,j};
(sum < T) ? ++i : --j;
}Binary search on answer
auto ok = [&](long long x){ /* feasibility for x */ return true; };
long long lo = L, hi = R;
while (lo < hi) {
long long mid = (lo + hi) / 2;
ok(mid) ? hi = mid : lo = mid + 1;
}
return lo;Monotonic stack (next greater index)
vector<int> nxt(n,-1), st;
for (int i=0;i<n;i++) {
while (!st.empty() && a[st.back()] < a[i]) { nxt[st.back()] = i; st.pop_back(); }
st.push_back(i);
}Union-Find (DSU)
struct DSU {
vector<int> p, r;
DSU(int n): p(n), r(n) { iota(p.begin(), p.end(), 0); }
int find(int x){ return p[x]==x ? x : p[x]=find(p[x]); }
bool unite(int a,int b){
a=find(a); b=find(b); if(a==b) return false;
if (r[a]<r[b]) swap(a,b);
p[b]=a; if(r[a]==r[b]) r[a]++;
return true;
}
};Grid BFS
queue<pair<int,int>> q; vector<vector<int>> dist(n, vector<int>(m,-1));
auto push=[&](int r,int c,int d){
if(r<0||c<0||r>=n||c>=m||dist[r][c]!=-1) return;
dist[r][c]=d; q.push({r,c});
};
push(sr,sc,0);
while(!q.empty()){
auto [r,c]=q.front(); q.pop();
for (auto [dr,dc] : vector<pair<int,int>>{{1,0},{-1,0},{0,1},{0,-1}})
push(r+dr,c+dc,dist[r][c]+1);
}Backtracking skeleton
vector<vector<int>> ans; vector<int> path;
function<void(int)> dfs = [&](int i){
if (/* done */) { ans.push_back(path); return; }
// choose
// dfs(next)
// unchoose
};
dfs(0);1D DP (knapsack-ish)
vector<int> dp(T+1, 0);
for (int w : items)
for (int t=T; t>=w; --t)
dp[t] = max(dp[t], dp[t-w] + value_of(w));- Restate & constraints: sizes, ranges, time/space targets.
- Signal → Pattern: window? subsequence? intervals? k-th? shortest path?
- State & invariants: define what indices/pointers/stack/heap represent.
- Edge tests first: empty, single, all equal, already sorted, negatives, duplicates, extremes.
-
Complexity & proof: confirm
O(n)/O(n log n); reason about correctness (invariants/exchange). - Optimize: memory reductions (rolling arrays), early exit, pruning.
Add a new problem
./scripts/new_problem.sh 0121 best-time-to-buy-and-sell-stock
# edit: problems/0121-best-time-to-buy-and-sell-stock/{main.cpp,test.cpp}
cmake --build --preset default
ctest --preset default -R 0121_best_time_to_buy_and_sell_stock --output-on-failure
git add problems/0121-best-time-to-buy-and-sell-stock
git commit -m "0121: solution + tests"
git pushWrite tests that teach
- Include prompt examples.
- Add edge cases (empty, single, duplicates, extremes).
- Add property checks (validity, uniqueness, monotonicity).
- Optional: randomized tests or oracle comparisons.
CMake auto-discover tip
Ensure problems/CMakeLists.txt uses CONFIGURE_DEPENDS so new problem dirs are re-scanned:
file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS "[0-9][0-9][0-9][0-9]-*")
foreach(child ${children})
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${child}/CMakeLists.txt")
add_subdirectory(${child})
endif()
endforeach()- Phase 1 (W1–2): arrays/strings, hashmaps, two pointers, sliding window.
- Phase 2 (W2–3): stacks (monotonic), intervals, binary search.
- Phase 3 (W3–4): linked lists, trees (DFS/BFS), recursion.
- Phase 4 (W4–6): graphs (BFS/DFS/topo/DSU/Dijkstra), DP (1D, grid, LIS/knapsack).
- Phase 5 (W6–8): backtracking, hard DP, mixed mocks + timed drills.
Target ~60–100 problems across patterns with planned re-drills.
- 0–5: clarify examples, pick approach, set complexity target.
- 5–25: code cleanly; narrate invariants/state.
- 25–35: test edge cases, fix defects.
- 35–40: analyze complexity, discuss tradeoffs.
- 40–45: micro-optimizations; summarize solution.
- Prefer
const vector<int>¶ms;reserve()when sizes are known. - Use
unordered_map/unordered_setfor averageO(1)lookups; watch load factors for huge inputs. - Prefer
vectorovernew[]; RAII by default. - Avoid signed/unsigned mix in loops; use
intindices consistently. - Name by role:
lo/hi,left/right,need/have,open/close. - Keep helpers
privatein classes; keep functions short & single-purpose.
Maintain a simple tracker (CSV/Markdown):
| ID | Title | Pattern | First Try | Re-do (D+1) | Re-do (D+7) | Notes |
|---|---|---|---|---|---|---|
| 0022 | Generate Parentheses | Backtracking | ✅ | ☐ | ☐ | opens>=closes; choose/unchoose |
| 0121 | Best Time to Buy & Sell | Greedy | ✅ | ☐ | ☐ | track minSoFar, max diff |
| 0005 | Longest Palindromic Substr | Expand center | ✅ | ☐ | ☐ | two centers per i |
Rule: every re-do is a from-scratch re-implementation (≤15 min, no peeking).
Happy grinding. Add the next problem with:
./scripts/new_problem.sh 0003 longest-substring-without-repeating-characters
cmake --build --preset default
ctest --preset default -R 0003_longest_substring_without_repeating_characters --output-on-failure