Skip to content

Mastering LeetCode (C ): A Practical Roadmap

Ragaad edited this page Oct 23, 2025 · 1 revision

Mastering LeetCode (C++): A Practical Roadmap

A focused plan to practice efficiently, write clean C++ solutions, and retain patterns. Designed to fit the leetcodeExamples repo workflow (CMake + GoogleTest).

Jump to:


Weekly Cadence (6–8 weeks)

Daily (~75–90 min)

  1. Warm-up (10 min): Re-implement a previously solved problem from memory (core idea only).
  2. 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.
  3. Notes (5 min): one-liner idea + traps.
  4. 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).


Pattern Toolkit (What to Look For)

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.

C++ Mini-Templates (Drop-ins)

The repo’s leetcode.hpp already includes a portable pch.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));

Solve Framework (Use Every Time)

  1. Restate & constraints: sizes, ranges, time/space targets.
  2. Signal → Pattern: window? subsequence? intervals? k-th? shortest path?
  3. State & invariants: define what indices/pointers/stack/heap represent.
  4. Edge tests first: empty, single, all equal, already sorted, negatives, duplicates, extremes.
  5. Complexity & proof: confirm O(n)/O(n log n); reason about correctness (invariants/exchange).
  6. Optimize: memory reductions (rolling arrays), early exit, pruning.

Using This Repo Effectively

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 push

Write 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()

Suggested Problem Sequencing

  • 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.


Interview Timing (45 min)

  • 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.

C++ Hygiene

  • Prefer const vector<int>& params; reserve() when sizes are known.
  • Use unordered_map/unordered_set for average O(1) lookups; watch load factors for huge inputs.
  • Prefer vector over new[]; RAII by default.
  • Avoid signed/unsigned mix in loops; use int indices consistently.
  • Name by role: lo/hi, left/right, need/have, open/close.
  • Keep helpers private in classes; keep functions short & single-purpose.

Tracking & Spaced Repetition

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