🏠 Hub πŸ’» DSA Master Notes Tier 1, 2, 3 β€’ 8+ YoE Guide
Page 1 / 12

Multi-Tier Strategy & 6-Week Master Roadmap

Targeted preparation framework for Senior & Staff (8+ YoE) algorithmic interviews
1

Senior Interview Realities: Tier 1 vs Tier 2 vs Tier 3

Know Your Audience
πŸš€
Tier 1: Big Tech
Meta β€’ Google β€’ Uber β€’ Stripe
  • Format: 2 Medium/Hard in 45 mins
  • Bar: Zero bugs + Big-O trade-offs
  • Focus: Speed, edge cases, optimal proofs
  • Key: Monotonic Stack, Graphs, Hard DP
πŸ—οΈ
Tier 2: Product Giants
Salesforce β€’ Atlassian β€’ Adobe β€’ Intuit
  • Format: 1 Hard or Custom DS design
  • Bar: Clean modular OOP & abstractions
  • Focus: Concurrency safety & clarity
  • Key: LRU/LFU Cache, Rate Limiters, Feeds
⚑
Tier 3: Rapid Scale-ups
Walmart β€’ Scale-ups β€’ Fintechs
  • Format: 100% Online Assessment pass
  • Bar: Pass hidden boundary test cases
  • Focus: Pragmatic code & core libs
  • Key: Arrays, Strings, HashMaps, Trees
2

The 45-Minute Live Interview Time Budget

⏱️
0 - 5 min
1. Clarify & Edge Cases
Clarify bounds ($N$, data types, duplicates, negatives). Write 2 custom edge cases before coding!
🧠
5 - 15 min
2. Formulate & Trade-offs
State brute-force ($O(N^2)$), then optimize to $O(N \log N)$ or $O(N)$. Confirm Big-O alignment first!
πŸ’»
15 - 35 min
3. Clean Modular Code
Write production-grade code with descriptive names, helper functions, and early guard clauses.
πŸ”
35 - 45 min
4. Dry-Run & Scale
Step through code line-by-line with sample input. Answer follow-ups on memory & concurrency.
3

Constraint-to-Pattern Meta Decision Matrix

Input Size ($N$) Target Time Complexity Primary DSA Patterns to Match
$N \le 12$ $O(N!)$ or $O(N^2 \cdot 2^N)$ Backtracking Permutations, Traveling Salesperson, TSP DP
$N \le 20 \dots 25$ $O(2^N)$ Subsets, Combination Sum, Bitmask DP
$N \le 100 \dots 500$ $O(N^3)$ or $O(N^4)$ Floyd-Warshall, Matrix Chain Multiplication, 3D Dynamic Programming
$N \le 2\,000 \dots 5\,000$ $O(N^2)$ 2D Matrix DP, Nested Two Pointers, All-Pairs Check
$N \le 10^5 \dots 10^6$ $O(N \log N)$ or $O(N)$ Sorting, Binary Search on Answer, Heaps, Sliding Window, Monotonic Stack, DSU
$N \ge 10^9$ $O(\log N)$ or $O(1)$ Pure Binary Search, Matrix Exponentiation, Math / Bitwise Hacks
🎯 Key Takeaway

"Senior interviews evaluate your decision framework & trade-offs, not rote syntax!"

"Never code in silence β€” interviewers want to see how you formulate hypotheses, think out loud, and pivot when stuck." 😊

Master Complexity Cheat Sheet & Sorting

1

Core Data Structure Time & Space Complexity Matrix

Data Structure Access / Search Insertion Deletion Space
Dynamic Array / Vector $O(1)$ / $O(N)$ $O(1)$ Amortized $O(N)$ $O(N)$
Doubly Linked List $O(N)$ / $O(N)$ $O(1)$ (with node ptr) $O(1)$ (with node ptr) $O(N)$
Hash Map / Hash Set $O(1)$ Avg, $O(N)$ Worst $O(1)$ Avg $O(1)$ Avg $O(N)$
Binary Search Tree (Balanced) $O(\log N)$ $O(\log N)$ $O(\log N)$ $O(N)$
Binary Heap (Priority Queue) $O(1)$ Peek, $O(N)$ Search $O(\log N)$ Push $O(\log N)$ Pop $O(N)$
Trie (Prefix Tree) $O(L)$ (where $L$ = word len) $O(L)$ $O(L)$ $O(N \cdot L \cdot \Sigma)$
Disjoint Set (Union-Find) $O(\alpha(N)) \approx O(1)$ $O(\alpha(N)) \approx O(1)$ β€” $O(N)$
2

Sorting Algorithms Comparison: In-Place vs Stable

⚑ QuickSort ($O(N \log N)$ avg, $O(N^2)$ worst)
In-Place ($O(\log N)$ stack), Unstable. Uses partition (Hoare's vs Lomuto). Standard for primitive types in standard libraries.
πŸ₯ž MergeSort ($O(N \log N)$ always)
Stable, requires $O(N)$ auxiliary memory. Preferred for sorting Linked Lists ($O(1)$ space) and external storage streams.
πŸ”οΈ HeapSort ($O(N \log N)$ always)
In-Place ($O(1)$ aux memory), Unstable. Builds heap in $O(N)$ via `heapify`, extracts min/max in $O(\log N)$.
πŸ”’ Counting / Radix Sort ($O(N + K)$)
Non-comparative, Stable. Ideal when integers lie in known range $K \ll N$. Used for sorting fixed-length strings/integers.
⚑ Senior Architectural Nuance: CPU Cache Locality
Arrays beat Linked Lists in real systems by a factor of 5-10x because sequential array elements reside in contiguous CPU L1/L2 cache lines, minimizing cache misses. Mentioning this in Tier 1/2 interviews demonstrates senior systems depth!

Arrays, Strings & Matrix Manipulations

1

Prefix Sum & Difference Array Techniques

  • Prefix Sum: Query sum in range $[L, R]$ in $O(1)$ after $O(N)$ precomputation: $\text{sum}(L, R) = P[R] - P[L-1]$.
  • HashMap + Prefix Sum (Subarray Sum Equals K): Maintain running prefix sum `curr_sum`. If `curr_sum - K` exists in map, add its frequency count. Solves contiguous subarray sum in $O(N)$ time & $O(N)$ space.
  • Difference Array (Range Updates in $O(1)$): To add $V$ to all indices in $[L, R]$, set $D[L] \mathrel{+}= V$ and $D[R+1] \mathrel{-}= V$. Take prefix sum of $D$ at the end.
2

Classic Matrix In-Place Transformations

πŸ”„ Rotate Image 90Β° Clockwise
Algorithm: 1. Transpose matrix ($M[i][j] \leftrightarrow M[j][i]$). 2. Reverse each row horizontally. Achieves $O(N^2)$ time, $O(1)$ in-place space!
πŸŒ€ Spiral Matrix Traversal
Maintain 4 boundaries: `top`, `bottom`, `left`, `right`. Traverse top row $\to$ right col $\to$ bottom row $\to$ left col, incrementing/decrementing bounds until crossed.
3

Code Template: Subarray Sum Equals K (C# & JavaScript)

πŸ’» C# (.NET 8) Implementation
public int SubarraySum(int[] nums, int k) {
    var prefixMap = new Dictionary<int, int> { [0] = 1 };
    int currSum = 0, count = 0;
    foreach (int x in nums) {
        currSum += x;
        if (prefixMap.TryGetValue(currSum - k, out int freq)) {
            count += freq;
        }
        prefixMap[currSum] = prefixMap.GetValueOrDefault(currSum, 0) + 1;
    }
    return count;
}

Two Pointers & Sliding Window Mastery

Convert nested $O(N^2)$ loops into blazing fast linear $O(N)$ passes
1

The 3 Two-Pointer Paradigms

1. Opposite Directional
`left = 0`, `right = N - 1`. Move inward based on target comparison.
2Sum II, 3Sum, Trapping Rain
2. Fast & Slow (Floyd's)
`slow = head`, `fast = head.next`. Move `fast` at 2x speed.
Cycle Detection, Middle of List
3. Sliding Window
`L = 0`, `R = 0`. Expand `R` to capture, shrink `L` to restore invariant.
Min Window, Longest Substring
πŸ” Visualizing the Window Invariant: Expand R βž” Shrink L
i=0
a
(past)
[
L ⬇
b
Window
i=2
c
Window
R ⬇
a
New Item
]
i=4
b
(unseen)
πŸ“ Window Length: `R - L + 1` = 3 elements ⚠️ If duplicate found: jump `L` forward to `lastSeen[c] + 1`
2

Universal Sliding Window Master Template

LengthOfLongestSubstring.cs β€” C# (.NET 8)
public int LengthOfLongestSubstring(string s) {
    var lastSeen = new Dictionary<char, int>();
    int left = 0, maxLen = 0;
    
    for (int right = 0; right < s.Length; right++) {
        char c = s[right];
        // Invariant Check: Shrink or jump left boundary if violated
        if (lastSeen.ContainsKey(c) && lastSeen[c] >= left) {
            left = lastSeen[c] + 1;
        }
        lastSeen[c] = right;
        maxLen = Math.Max(maxLen, right - left + 1);
    }
    return maxLen;
}
🎯 Key Takeaway

"Both pointers together visit each element at most TWICE βž” Strict $O(N)$ Time!"

"Never write nested while loops with separate index resets β€” maintain the window invariant and slide forward." 😊

Custom Data Structures & LRU / LFU Cache

The #1 Tier 2 interview favorite: combine primitives to achieve strict $O(1)$ operations
1

LRU Cache Architecture: HashMap + Doubly Linked List

πŸ“ Internal Architecture: HashMap + Doubly Linked List (DLL) All Operations $O(1)$
SENTINEL
dummy head
⇄
MOST RECENT
[K: 1, V: "A"]
⇄
IN-BETWEEN
[K: 2, V: "B"]
⇄
LEAST RECENT (LRU)
[K: 3, V: "C"]
⇄
SENTINEL
dummy tail
⚑ Get(k) / Put(k, v): Move node to head.next in $O(1)$ πŸ—‘οΈ Evict on Full: Remove node before tail.prev in $O(1)$ πŸ—ΊοΈ HashMap: `map[key] βž” Node` reference
2

Production-Grade C# LRU Cache Implementation

LRUCache.cs β€” Sentinel Nodes Pattern
public class LRUCache {
    private class Node {
        public int Key, Val;
        public Node Prev, Next;
        public Node(int k = 0, int v = 0) { Key = k; Val = v; }
    }

    private readonly int _cap;
    private readonly Dictionary<int, Node> _map;
    private readonly Node _head, _tail; // Dummy boundary sentinels

    public LRUCache(int capacity) {
        _cap = capacity;
        _map = new Dictionary<int, Node>();
        _head = new Node(); _tail = new Node();
        _head.Next = _tail; _tail.Prev = _head;
    }

    public int Get(int key) {
        if (!_map.TryGetValue(key, out var node)) return -1;
        Remove(node);
        InsertHead(node); // Mark as Most Recently Used
        return node.Val;
    }

    public void Put(int key, int value) {
        if (_map.TryGetValue(key, out var existing)) {
            Remove(existing);
        } else if (_map.Count == _cap) {
            var lru = _tail.Prev; // Evict least recently used
            Remove(lru);
            _map.Remove(lru.Key);
        }
        var fresh = new Node(key, value);
        InsertHead(fresh);
        _map[key] = fresh;
    }

    private void Remove(Node n) { n.Prev.Next = n.Next; n.Next.Prev = n.Prev; }
    private void InsertHead(Node n) {
        n.Next = _head.Next; n.Prev = _head;
        _head.Next.Prev = n; _head.Next = n;
    }
}
🎯 Key Takeaway

"Dummy Head & Tail sentinels eliminate 100% of null checks & edge case bugs in live interviews!"

"Never write special conditions for inserting into an empty list β€” sentinels guarantee head.Next and tail.Prev always exist." 😊

3

Other Must-Know Custom Data Structure Designs (Tier 2 Favorites)

🎲 Insert Delete GetRandom O(1)
Use `List<int>` for $O(1)$ random indexing + `Dictionary<int, int>` (val $\to$ index). On delete, swap target with last element in $O(1)$.
🐦 Design Twitter / News Feed
`Dictionary<int, List<Tweet>>` + `PriorityQueue<Tweet, int>` for K-way merging the recent tweets of followed users in $O(K \log F)$.

Binary Search & Monotonic Answer Space

1

Binary Search Invariant Templates (C#)

  • Standard Invariant: `low = 0, high = N - 1`. While `low <= high`, `mid = low + (high - low) / 2` (prevents integer overflow in C#).
  • Rotated Sorted Array Search: At least one half (`[low, mid]` or `[mid, high]`) is always strictly sorted. Check if target lies in the sorted half to determine which boundary to discard.
2

Binary Search on Answer Space (`check(mid)` Framework)

When to use: "Find the Minimum X such that condition is satisfied"
If `check(mid)` is Monotonic (i.e. if feasible for $K$, then feasible for all values $> K$), we binary search directly over the range of possible answers $[1, \max(\text{values})]$ in $O(N \log(\text{Range}))$.
πŸ’» C# Koko Eating Bananas / Ship Packages Master Template
public int MinEatingSpeed(int[] piles, int h) {
    bool CanFinish(int speed) {
        long totalHours = 0;
        foreach (int p in piles) {
            totalHours += (p + speed - 1L) / speed; // Ceiling division
        }
        return totalHours <= h;
    }

    int low = 1, high = piles.Max();
    int ans = high;
    while (low <= high) {
        int mid = low + (high - low) / 2;
        if (CanFinish(mid)) {
            ans = mid;
            high = mid - 1; // Feasible! Try finding a smaller speed
        } else {
            low = mid + 1;  // Too slow, increase speed
        }
    }
    return ans;
}

Monotonic Stack, Deque & Priority Queues

1

Monotonic Stack: Next Greater Element in $O(N)$ (C#)

  • Concept: Maintain stack elements in strictly increasing or decreasing order. When a new element violates the monotonicity, pop elements and process their answers!
  • Key Applications: Daily Temperatures, Next Greater Element, Largest Rectangle in Histogram, Trapping Rain Water, Asteroid Collision.
πŸ’» C# Daily Temperatures with Stack<int>
public int[] DailyTemperatures(int[] temperatures) {
    int n = temperatures.Length;
    var res = new int[n];
    var stack = new Stack<int>(); // Stores indices
    
    for (int i = 0; i < n; i++) {
        while (stack.Count > 0 && temperatures[i] > temperatures[stack.Peek()]) {
            int prevIdx = stack.Pop();
            res[prevIdx] = i - prevIdx;
        }
        stack.Push(i);
    }
    return res;
}
2

Two Heaps: Median from Data Stream (C# .NET 8 PriorityQueue)

Max-Heap (Left Half)
`PriorityQueue<int, int>` with negative priority for Max-Heap behavior. Root has maximum of smaller half.
Min-Heap (Right Half)
`PriorityQueue<int, int>` with natural priority. Root has minimum of larger half.
⚑ Median Invariant
Maintain size property: `maxHeap.Count == minHeap.Count` or `maxHeap.Count == minHeap.Count + 1`. Median is either `maxHeap.Peek()` or average of both roots in $O(1)$ time!

Trees, BST, LCA & Trie (Prefix Trees)

1

Tree DFS: Lowest Common Ancestor (C#)

πŸ’» C# LCA in Binary Tree
public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if (root == null || root == p || root == q) return root;
    var left = LowestCommonAncestor(root.left, p, q);
    var right = LowestCommonAncestor(root.right, p, q);
    if (left != null && right != null) return root; // Split point
    return left ?? right;
}
2

Trie (Prefix Tree) Master Template (C#)

πŸ’» C# Trie Implementation
public class TrieNode {
    public Dictionary<char, TrieNode> Children = new();
    public bool IsWord = false;
}

public class Trie {
    private readonly TrieNode _root = new();

    public void Insert(string word) {
        var node = _root;
        foreach (char c in word) {
            if (!node.Children.ContainsKey(c)) node.Children[c] = new TrieNode();
            node = node.Children[c];
        }
        node.IsWord = true;
    }

    public bool StartsWith(string prefix) {
        var node = _root;
        foreach (char c in prefix) {
            if (!node.Children.TryGetValue(c, out node)) return false;
        }
        return true;
    }
}

Graph Algorithms: BFS, DFS, TopoSort & DSU

1

Topological Sort (Kahn's In-Degree Algorithm in C#)

  • When to use: Build order, task scheduling with dependencies, course prerequisites, cycle detection in DAGs.
  • Algorithm: 1. Calculate in-degrees for all $V$ nodes. 2. Push nodes with `in_degree == 0` to `Queue<int>`. 3. While queue not empty, pop $u$, decrement neighbors' in-degree. If neighbor becomes 0, push to queue. If processed count $< V$, a cycle exists!
2

Union-Find (DSU) with Path Compression & Rank (C#)

πŸ’» C# Disjoint Set Union O(Ξ±(N)) Template
public class UnionFind {
    private readonly int[] _parent;
    private readonly int[] _rank;

    public UnionFind(int n) {
        _parent = new int[n];
        _rank = new int[n];
        for (int i = 0; i < n; i++) { _parent[i] = i; _rank[i] = 1; }
    }

    public int Find(int i) {
        if (_parent[i] != i) {
            _parent[i] = Find(_parent[i]); // Path compression
        }
        return _parent[i];
    }

    public bool Union(int i, int j) {
        int rootI = Find(i), rootJ = Find(j);
        if (rootI == rootJ) return false; // Cycle detected!
        if (_rank[rootI] < _rank[rootJ]) (rootI, rootJ) = (rootJ, rootI);
        _parent[rootJ] = rootI;
        _rank[rootI] += _rank[rootJ];
        return true;
    }
}
3

Dijkstra's Shortest Path Algorithm (C#)

  • Min-Heap PriorityQueue: Tracks `(node, dist)`. Initialize `dist[start] = 0`, all others $\infty$. Process min node, relax edges in $O((V + E) \log V)$ using `PriorityQueue<int, int>`. Note: Dijkstra fails on negative weight edges (use Bellman-Ford).

Dynamic Programming & Backtracking

1

The 5-Step DP Formulation Framework

1. State Definition
`dp[i][j]` = optimal answer for subarray $0 \dots i$ with constraint $j$.
2. Choice & Recurrence
Formulate transition: `dp[i] = min(dp[i - c] + 1)` (e.g. Coin Change).
3. Base Cases
Identify known starting values (e.g. `dp[0] = 0`, empty string states).
4. Rolling Array Optimization
If `dp[i]` only depends on `dp[i-1]`, reduce $O(N^2)$ space to $O(N)$!
2

Top 4 DP Problem Archetypes

Pattern Classic Problem State Transition
1D Subarray / Jump House Robber / Coin Change `dp[i] = max(dp[i-1], dp[i-2] + nums[i])`
2D Grid / Matrix Unique Paths / Edit Distance `dp[i][j] = dp[i-1][j] + dp[i][j-1]`
Two Strings / LCS Longest Common Subsequence If $s_1[i] == s_2[j] \implies dp[i-1][j-1] + 1$, else $\max(dp[i-1][j], dp[i][j-1])$
Knapsack 0/1 Partition Equal Subset Sum `dp[w] = dp[w] | dp[w - num]` (iterate backwards to avoid reuse)
3

Code Template: Coin Change 1D DP (C#)

πŸ’» C# Bottom-Up 1D Array Dynamic Programming
public int CoinChange(int[] coins, int amount) {
    var dp = new int[amount + 1];
    Array.Fill(dp, amount + 1); // Sentinel max value
    dp[0] = 0;
    
    for (int a = 1; a <= amount; a++) {
        foreach (int c in coins) {
            if (a - c >= 0) {
                dp[a] = Math.Min(dp[a], dp[a - c] + 1);
            }
        }
    }
    return dp[amount] > amount ? -1 : dp[amount];
}

Intervals, Greedy & Bitwise / Concurrency

1

Intervals Master Framework: Sort by Start Time

  • Merge Overlapping Intervals: Sort intervals by `start`. Iterate through list: if `curr.start <= prev.end`, merge by updating `prev.end = max(prev.end, curr.end)`. Otherwise append new interval.
  • Meeting Rooms II (Min Conference Rooms): Min-Heap of end times. Sort meetings by start time. If `start >= heap.peek()`, pop room (reused). Push current end time. `len(heap)` is the room count!
2

Bit Manipulation Ninja Tricks

XOR Cancellation
$x \oplus x = 0$, $x \oplus 0 = x$. Solves Single Number in $O(N)$ time & $O(1)$ space.
Clear Lowest Set Bit
`n & (n - 1)` removes the lowest set bit. Counts set bits (Hamming weight) in $O(\text{set bits})$.
Power of Two Check
`n > 0 and (n & (n - 1)) == 0` checks if $n$ is a power of 2 in $O(1)$!
3

Thread-Safe Data Structures (C# Senior / Tier 2 Focus)

πŸ’» C# Thread-Safe Bounded Blocking Queue
public class BoundedBlockingQueue {
    private readonly Queue<int> _queue = new();
    private readonly int _capacity;
    private readonly object _lock = new();

    public BoundedBlockingQueue(int capacity) { _capacity = capacity; }

    public void Enqueue(int element) {
        lock (_lock) {
            while (_queue.Count == _capacity) {
                Monitor.Wait(_lock); // Handle spurious wakeups
            }
            _queue.Enqueue(element);
            Monitor.PulseAll(_lock);
        }
    }

    public int Dequeue() {
        lock (_lock) {
            while (_queue.Count == 0) {
                Monitor.Wait(_lock);
            }
            int item = _queue.Dequeue();
            Monitor.PulseAll(_lock);
            return item;
        }
    }
}

Tier 1, 2, 3 Rubrics & Live Interview Execution

1

The 6-Step Live Interview Protocol

Step 1: Clarify Constraints
Array bounds, negative values, duplicates, memory limits, edge cases (empty list, 1 element).
Step 2: Propose Naive & Optimal
State brute-force ($O(N^2)$), then introduce $O(N \log N)$ or $O(N)$ with data structure rationale.
Step 3: State Big-O First
State Time and Space complexity upfront to get interviewer nod before writing code!
Step 4: Clean Production Code
Write clean, idiomatic code with helper functions, meaningful variable names, and early guards.
Step 5: Systematic Dry Run
Trace pointers (`L`, `R`, `mid`, `stack`) with a small table against a sample input. Catch bugs yourself!
Step 6: Follow-up Scale
Explain streaming data handling, disk spilling, and distributed parallelization.
2

Top 10 Senior Red Flags to Avoid in Coding Rounds

  • ❌ Jumping straight into code without explaining your approach or confirming alignment.
  • ❌ Coding in complete silence for 10 minutes without thinking aloud.
  • ❌ Using cryptic 1-letter variables ($a, b, c, x, y$) instead of clean domain names (`left_max`, `in_degree`).
  • ❌ Ignoring interviewer hints β€” hints are deliberate alignment tests, not deductions.
  • ❌ Saying "My code works!" without running a structured manual dry-run trace.
🎯 Final Takeaway for 8+ YoE Candidates
Seniors are hired for sound engineering judgment, code clarity, and architectural composure under pressure. Master these 15 core patterns, communicate with confidence, and crush your interviews across all tiers!
πŸ“– DSA Master Table of Contents