Interview Importance: π΄ Critical β A structured 8-week plan designed for full-time professionals to achieve FAANG-level Medium problem confidence with just 45-60 minutes daily commitment.
This comprehensive guide is specifically designed for working professionals who:
Timeline: 8 weeks (2 months)
Target: FAANG-level Medium confidence
Volume: ~90 problems (curated, not random)
Time: 45-60 mins/day (Mon-Fri) + 2-3 hrs (Sat/Sun)
Focus: High pattern repetition + spaced learning
Success: Solve 2 mediums in 75 minutes reliably
| Aspect | Traditional Approach | This Plan |
|---|---|---|
| Problem Selection | Random 500+ problems | 90 curated with pattern focus |
| Time Investment | 3-4 hours daily | 45-60 mins weekdays, realistic for working professionals |
| Learning Method | One-time solve | Spaced repetition (2 days + 7 days) |
| Pattern Coverage | Scattered | 8 core patterns mastered deeply |
| Progress Tracking | None | Weekly checkpoints with clear metrics |
Real-World Analogy:
Think of this like learning a musical instrument. You don't become a pianist by playing 500 different songs once. You master 20-30 pieces through deliberate practice, repetition, and pattern recognition. Similarly, these 90 problems teach you the 8 patterns that cover 80% of interview questions.
Time Investment Per Problem:
βββββββββββββββββββββββββββββββββββββββββββββββ
β 25-35 min: Genuine attempt (even if stuck) β
β 10-15 min: Study solution + understand β
β 20-30 min: Re-solve without help β
βββββββββββββββββββββββββββββββββββββββββββββββ
Total: ~60 minutes per problem
Why this matters:
For every problem solved, write:
1. Pattern + Invariant (2 lines max)
// Example: Two Sum Pattern: HashMap for O(1) lookup Invariant: complement = target - current always exists in map when solution exists
2. Time + Space Complexity
// Time: O(n) - single pass through array // Space: O(n) - hashmap stores up to n elements
Day 1: Solve problem for first time
Day 3: Re-solve (2-day gap) β Critical!
Day 8: Re-solve (7-day gap) β Mastery!
Why this matters:
π― Goal: Stop feeling "blank" when seeing array problems
π Problem Distribution: 12 problems (8 Easy, 4 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| 1 | Move Zeroes | Easy | Two Pointers | LC 283 |
| 2 | Remove Element | Easy | Two Pointers | LC 27 |
| 3 | Squares of a Sorted Array | Easy | Two Pointers | LC 977 |
| 4 | Two Sum | Easy | HashMap | LC 1 |
| 5 | Best Time to Buy and Sell Stock | Easy | Single Pass | LC 121 |
| 6 | Valid Palindrome | Easy | Two Pointers | LC 125 |
| 7 | Reverse String | Easy | Two Pointers | LC 344 |
| 8 | Merge Sorted Array | Easy | Two Pointers | LC 88 |
| 9 | Remove Duplicates from Sorted Array | Easy | Two Pointers | LC 26 |
| 10 | Container With Most Water | Medium | Two Pointers | LC 11 |
| 11 | Trapping Rain Water | Medium | Two Pointers | LC 42 |
| 12 | 3Sum | Medium | Two Pointers | LC 15 |
Weekend Tasks:
β Re-solve: Move Zeroes, Remove Element, Container With Most Water
β Create your "Two Pointers Template"
β Write down: "When do I use two pointers?"
Two Pointers Template:
// Pattern 1: Opposite Direction (Converging) const twoPointerConverge = (arr) => { let left = 0; let right = arr.length - 1; while (left < right) { // Process arr[left] and arr[right] // Move pointers based on condition if (condition) left++; else right--; } }; // Pattern 2: Same Direction (Fast-Slow) const twoPointerSameDir = (arr) => { let slow = 0; for (let fast = 0; fast < arr.length; fast++) { if (shouldKeep(arr[fast])) { arr[slow] = arr[fast]; slow++; } } return slow; // New length };
π― Goal: Build "window thinking" automatically
π Problem Distribution: 12 problems (4 Easy, 8 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| 1 | Longest Substring Without Repeating Characters | Medium | Sliding Window | LC 3 |
| 2 | Minimum Size Subarray Sum | Medium | Sliding Window | LC 209 |
| 3 | Max Consecutive Ones III | Medium | Sliding Window | LC 1004 |
| 4 | Permutation in String | Medium | Sliding Window | LC 567 |
| 5 | Find All Anagrams in a String | Medium | Sliding Window | LC 438 |
| 6 | Fruits Into Baskets | Medium | Sliding Window | LC 904 |
| 7 | Subarray Sum Equals K | Medium | Prefix Sum + HashMap | LC 560 |
| 8 | Contains Duplicate | Easy | HashMap | LC 217 |
| 9 | Group Anagrams | Medium | HashMap | LC 49 |
| 10 | Top K Frequent Elements | Medium | HashMap + Bucket | LC 347 |
| 11 | Valid Anagram | Easy | HashMap | LC 242 |
| 12 | Product of Array Except Self | Medium | Prefix/Suffix | LC 238 |
Weekend Tasks:
β Re-solve: Longest Substring (#1), Permutation in String (#4), Subarray Sum (#7)
β Create "Sliding Window Checklist"
β Write down: "Fixed vs Variable window - when to use?"
Sliding Window Checklist:
// Variable-size window template const slidingWindowVariable = (arr, target) => { let left = 0; let windowSum = 0; let result = 0; for (let right = 0; right < arr.length; right++) { // 1. Expand window (add arr[right]) windowSum += arr[right]; // 2. Shrink window while condition invalid while (windowSum > target) { windowSum -= arr[left]; left++; } // 3. Update result result = Math.max(result, right - left + 1); } return result; }; // Fixed-size window template const slidingWindowFixed = (arr, k) => { let windowSum = 0; // Initialize first window for (let i = 0; i < k; i++) { windowSum += arr[i]; } let maxSum = windowSum; // Slide window for (let i = k; i < arr.length; i++) { windowSum += arr[i] - arr[i - k]; // Add new, remove old maxSum = Math.max(maxSum, windowSum); } return maxSum; };
π― Goal: Handle "next greater/smaller" questions instinctively
π Problem Distribution: 10 problems (3 Easy, 7 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| 1 | Valid Parentheses | Easy | Stack | LC 20 |
| 2 | Min Stack | Easy | Stack | LC 155 |
| 3 | Daily Temperatures | Medium | Monotonic Stack | LC 739 |
| 4 | Next Greater Element I | Easy | Monotonic Stack | LC 496 |
| 5 | Next Greater Element II | Medium | Monotonic Stack | LC 503 |
| 6 | Evaluate Reverse Polish Notation | Medium | Stack | LC 150 |
| 7 | Largest Rectangle in Histogram | Hard | Monotonic Stack | LC 84 |
| 8 | Trapping Rain Water (Stack) | Medium | Monotonic Stack | LC 42 |
| 9 | Simplify Path | Medium | Stack | LC 71 |
| 10 | Remove All Adjacent Duplicates II | Medium | Stack | LC 1209 |
Weekend Tasks:
β Re-solve: Daily Temperatures, Largest Rectangle (understand, don't memorize)
β Write: "When to use stack? When to use monotonic stack?"
Monotonic Stack Pattern:
// Next Greater Element (Decreasing Stack) const nextGreaterElement = (arr) => { const result = new Array(arr.length).fill(-1); const stack = []; // Store indices for (let i = 0; i < arr.length; i++) { // While current is greater than stack top while (stack.length > 0 && arr[i] > arr[stack[stack.length - 1]]) { const idx = stack.pop(); result[idx] = arr[i]; // Found next greater for idx } stack.push(i); } return result; }; // Pattern Recognition: // "next greater" β decreasing stack // "next smaller" β increasing stack
π― Goal: Binary search should feel like a tool, not fear
π Problem Distribution: 11 problems (5 Easy, 6 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| 1 | Binary Search | Easy | Binary Search | LC 704 |
| 2 | Search Insert Position | Easy | Binary Search | LC 35 |
| 3 | Find First and Last Position | Medium | Binary Search | LC 34 |
| 4 | Search in Rotated Sorted Array | Medium | Binary Search | LC 33 |
| 5 | Find Minimum in Rotated Array | Medium | Binary Search | LC 153 |
| 6 | Peak Index in a Mountain Array | Easy | Binary Search | LC 852 |
| 7 | Koko Eating Bananas | Medium | Answer Binary Search | LC 875 |
| 8 | Capacity To Ship Packages | Medium | Answer Binary Search | LC 1011 |
| 9 | Median of Two Sorted Arrays | Hard | Binary Search | LC 4 |
| 10 | Square Root (Integer) | Easy | Binary Search | LC 69 |
| 11 | Search a 2D Matrix | Medium | Binary Search | LC 74 |
Weekend Tasks:
β Create 2 templates:
1. "Find exact element" template
2. "Min feasible / Max feasible" (answer binary search) template
β Re-solve: Koko Eating Bananas, Capacity To Ship Packages
Binary Search Templates:
// Template 1: Find Exact Element const binarySearchExact = (arr, target) => { let left = 0; let right = arr.length - 1; while (left <= right) { const mid = Math.floor(left + (right - left) / 2); if (arr[mid] === target) return mid; if (arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; // Not found }; // Template 2: Answer Binary Search (Min Feasible) const answerBinarySearch = (arr, condition) => { let left = minPossible; let right = maxPossible; let result = -1; while (left <= right) { const mid = Math.floor(left + (right - left) / 2); if (isFeasible(mid)) { result = mid; // Record feasible answer right = mid - 1; // Try to find smaller } else { left = mid + 1; // Need larger value } } return result; }; // Pattern: "minimum days/speed/capacity" β Answer Binary Search
π― Goal: Stop making pointer mistakes
π Problem Distribution: 10 problems (6 Easy, 4 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| 1 | Reverse Linked List | Easy | Pointer Manipulation | LC 206 |
| 2 | Merge Two Sorted Lists | Easy | Two Pointers | LC 21 |
| 3 | Linked List Cycle | Easy | Fast/Slow Pointer | LC 141 |
| 4 | Middle of the Linked List | Easy | Fast/Slow Pointer | LC 876 |
| 5 | Remove Nth Node From End | Medium | Two Pointers | LC 19 |
| 6 | Reorder List | Medium | Multiple Patterns | LC 143 |
| 7 | Intersection of Two Lists | Easy | Two Pointers | LC 160 |
| 8 | Add Two Numbers | Medium | Linked List | LC 2 |
| 9 | Palindrome Linked List | Easy | Fast/Slow + Reverse | LC 234 |
| 10 | Copy List with Random Pointer | Medium | HashMap | LC 138 |
Weekend Tasks:
β Re-solve: Reverse LL, Remove Nth Node, Reorder List
β Master: "Why dummy node?" and "When fast/slow?"
Linked List Patterns:
// Pattern 1: Reverse Linked List const reverseList = (head) => { let prev = null; let curr = head; while (curr) { const next = curr.next; // Save next curr.next = prev; // Reverse pointer prev = curr; // Move prev curr = next; // Move curr } return prev; // New head }; // Pattern 2: Fast/Slow Pointer (Find Middle) const findMiddle = (head) => { let slow = head; let fast = head; while (fast && fast.next) { slow = slow.next; // Move 1 step fast = fast.next.next; // Move 2 steps } return slow; // Middle node }; // Pattern 3: Dummy Node (Avoid Edge Cases) const mergeLists = (l1, l2) => { const dummy = new ListNode(0); let curr = dummy; while (l1 && l2) { if (l1.val < l2.val) { curr.next = l1; l1 = l1.next; } else { curr.next = l2; l2 = l2.next; } curr = curr.next; } curr.next = l1 || l2; return dummy.next; // Skip dummy };
π― Goal: Recursion clarity + traversal comfort
π Problem Distribution: 12 problems (7 Easy, 5 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| 1 | Maximum Depth of Binary Tree | Easy | DFS | LC 104 |
| 2 | Invert Binary Tree | Easy | DFS | LC 226 |
| 3 | Diameter of Binary Tree | Easy | DFS | LC 543 |
| 4 | Balanced Binary Tree | Easy | DFS | LC 110 |
| 5 | Same Tree | Easy | DFS | LC 100 |
| 6 | Subtree of Another Tree | Easy | DFS | LC 572 |
| 7 | Binary Tree Level Order | Medium | BFS | LC 102 |
| 8 | Validate Binary Search Tree | Medium | DFS | LC 98 |
| 9 | Lowest Common Ancestor BST | Easy | BST Property | LC 235 |
| 10 | Path Sum | Easy | DFS | LC 112 |
| 11 | Kth Smallest Element BST | Medium | In-order DFS | LC 230 |
| 12 | Construct Tree from Pre+In | Medium | Recursion | LC 105 |
Weekend Tasks:
β Re-solve: Level Order, Validate BST, Diameter
β Master: DFS vs BFS decision making
Tree Traversal Patterns:
// Pattern 1: DFS Recursion (Most Common) const maxDepth = (root) => { if (!root) return 0; // Base case const left = maxDepth(root.left); const right = maxDepth(root.right); return Math.max(left, right) + 1; }; // Pattern 2: BFS (Level Order) const levelOrder = (root) => { if (!root) return []; const result = []; const queue = [root]; while (queue.length > 0) { const levelSize = queue.length; const currentLevel = []; for (let i = 0; i < levelSize; i++) { const node = queue.shift(); currentLevel.push(node.val); if (node.left) queue.push(node.left); if (node.right) queue.push(node.right); } result.push(currentLevel); } return result; }; // Pattern 3: BST Validation (Range Check) const isValidBST = (root, min = -Infinity, max = Infinity) => { if (!root) return true; if (root.val <= min || root.val >= max) return false; return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max); }; // Decision: DFS when you need depth/paths, BFS when you need levels
π― Goal: Cover high-frequency interview patterns
π Problem Distribution: 11 problems (2 Easy, 9 Medium)
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| Heaps | ||||
| 1 | Kth Largest Element in Array | Medium | Heap/QuickSelect | LC 215 |
| 2 | Top K Frequent Elements | Medium | Heap + HashMap | LC 347 |
| 3 | Find Median from Data Stream | Hard | Two Heaps | LC 295 |
| Intervals | ||||
| 4 | Merge Intervals | Medium | Sorting + Merge | LC 56 |
| 5 | Insert Interval | Medium | Linear Scan | LC 57 |
| 6 | Non-overlapping Intervals | Medium | Greedy | LC 435 |
| 7 | Meeting Rooms II | Medium | Heap | LC 253 (Premium) |
| Greedy | ||||
| 8 | Jump Game | Medium | Greedy | LC 55 |
| 9 | Gas Station | Medium | Greedy | LC 134 |
| 10 | Partition Labels | Medium | Greedy | LC 763 |
| 11 | Min Add Parentheses Valid | Medium | Greedy | LC 921 |
Weekend Tasks:
β Re-solve: Merge Intervals, Meeting Rooms, Kth Largest
β Master: "When is greedy optimal?"
Key Patterns:
// Pattern 1: Merge Intervals const mergeIntervals = (intervals) => { intervals.sort((a, b) => a[0] - b[0]); const result = [intervals[0]]; for (let i = 1; i < intervals.length; i++) { const last = result[result.length - 1]; if (intervals[i][0] <= last[1]) { // Overlapping: merge last[1] = Math.max(last[1], intervals[i][1]); } else { // Non-overlapping: add new result.push(intervals[i]); } } return result; }; // Pattern 2: Min Heap (Using array for simplicity) class MinHeap { constructor() { this.heap = []; } push(val) { this.heap.push(val); this.bubbleUp(); } pop() { if (this.heap.length === 0) return null; const min = this.heap[0]; const last = this.heap.pop(); if (this.heap.length > 0) { this.heap[0] = last; this.bubbleDown(); } return min; } peek() { return this.heap[0]; } size() { return this.heap.length; } bubbleUp() { let idx = this.heap.length - 1; while (idx > 0) { const parentIdx = Math.floor((idx - 1) / 2); if (this.heap[idx] >= this.heap[parentIdx]) break; [this.heap[idx], this.heap[parentIdx]] = [this.heap[parentIdx], this.heap[idx]]; idx = parentIdx; } } bubbleDown() { let idx = 0; while (true) { const leftIdx = 2 * idx + 1; const rightIdx = 2 * idx + 2; let smallest = idx; if (leftIdx < this.heap.length && this.heap[leftIdx] < this.heap[smallest]) { smallest = leftIdx; } if (rightIdx < this.heap.length && this.heap[rightIdx] < this.heap[smallest]) { smallest = rightIdx; } if (smallest === idx) break; [this.heap[idx], this.heap[smallest]] = [this.heap[smallest], this.heap[idx]]; idx = smallest; } } } // Greedy Pattern: "Can we make local optimal choice?" // If yes β Greedy works // If no β Need DP
π― Goal: Convert knowledge into interview performance
π Problem Distribution: 12 problems + 2 mock interviews
| # | Problem | Difficulty | Pattern | LeetCode |
|---|---|---|---|---|
| Graphs | ||||
| 1 | Number of Islands | Medium | DFS/BFS | LC 200 |
| 2 | Flood Fill | Easy | DFS/BFS | LC 733 |
| 3 | Clone Graph | Medium | DFS + HashMap | LC 133 |
| 4 | Course Schedule | Medium | Topological Sort | LC 207 |
| 5 | Pacific Atlantic Water Flow | Medium | DFS | LC 417 |
| 6 | Rotting Oranges | Medium | BFS | LC 994 |
| DP Intro | ||||
| 7 | Climbing Stairs | Easy | DP | LC 70 |
| 8 | House Robber | Medium | DP | LC 198 |
| 9 | House Robber II | Medium | DP | LC 213 |
| 10 | Coin Change | Medium | DP | LC 322 |
| 11 | Longest Increasing Subseq | Medium | DP | LC 300 |
| 12 | Longest Common Subseq | Medium | DP | LC 1143 |
Mock Interviews (Critical!):
Mock 1: 1 Easy + 1 Medium (60 minutes)
- Simulate real interview: talk out loud
- Use timer: 25 min Easy, 35 min Medium
- Practice: "Let me think through this..."
Mock 2: 1 Medium Deep-Dive (60 minutes)
- 45 min: Solve medium problem
- 15 min: Explain solution + optimizations
- Practice: Complexity analysis explanation
Graph Patterns:
// Pattern 1: DFS on Grid const numIslands = (grid) => { if (!grid.length) return 0; let count = 0; const dfs = (i, j) => { if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] === '0') { return; } grid[i][j] = '0'; // Mark visited dfs(i + 1, j); dfs(i - 1, j); dfs(i, j + 1); dfs(i, j - 1); }; for (let i = 0; i < grid.length; i++) { for (let j = 0; j < grid[0].length; j++) { if (grid[i][j] === '1') { count++; dfs(i, j); } } } return count; }; // Pattern 2: Simple DP (Climbing Stairs) const climbStairs = (n) => { if (n <= 2) return n; let prev2 = 1; // dp[i-2] let prev1 = 2; // dp[i-1] for (let i = 3; i <= n; i++) { const curr = prev1 + prev2; prev2 = prev1; prev1 = curr; } return prev1; }; // DP Pattern Recognition: // "count ways" β DP // "minimum/maximum" + "all possibilities" β DP // Can we break into subproblems? β DP
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 5 min: Recall Yesterday's Pattern β
β - What was the pattern? β
β - What was the key insight? β
β - Write 1-line summary β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 25-35 min: Solve Today's Problem β
β - Read problem carefully β
β - Identify pattern β
β - Attempt solution (25-35 min max) β
β - If stuck at 25 min β Look at solution β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 10-15 min: Write Clean Solution + Document β
β - Write clean code β
β - Dry run with example β
β - Document: Pattern + Invariant β
β - Document: Time + Space complexity β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Example Daily Log:
// Day 12: Longest Substring Without Repeating Characters // Pattern: Sliding Window (variable size) // Invariant: window contains no duplicates (hashset tracks) // Time: O(n) - each char visited at most twice // Space: O(min(n, m)) - m = charset size // Key Insight: Expand right, shrink left when duplicate found // Mistake I made: Forgot to remove left char from set when shrinking
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 60-90 min: Re-solve 3 Problems (No Help!) β
β - Pick from 2 days ago and 7 days ago β
β - Set timer: 25 min each β
β - NO peeking at solutions β
β - If stuck: try 5 more min, then peek β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 45-60 min: 1 Timed Session β
β - Fresh medium problem β
β - 35 min timer β
β - Talk out loud (practice interviewing) β
β - Record: what slowed you down? β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 30-45 min: Pattern Notes Review β
β - Review week's patterns β
β - Identify weak spots β
β - Write: "When to use X vs Y?" β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
You should be able to:
Self-Test:
Problem: "Find longest subarray with sum β€ K"
Can you:
β Identify it's sliding window in 30 seconds?
β Write the template from memory?
β Solve in 20-25 minutes?
If No: Review Week 1-2 problems again
You should be able to:
Self-Test:
Problem: "Minimum speed to finish tasks in D days"
Can you:
β Recognize it's answer binary search immediately?
β Define the search space (min, max)?
β Write isFeasible() function?
β Solve in 25 minutes?
If No: Redo Week 4 problems, focus on "why binary search works here"
You should be able to:
Self-Test:
Problem: "Find all paths that sum to target"
Can you:
β Choose DFS over BFS immediately?
β Write base case correctly?
β Handle backtracking if needed?
β Solve in 30 minutes?
If No: Redo tree problems, draw out recursion tree
You should be able to:
Final Self-Test:
Pick 2 random medium problems you haven't solved:
β Solve both in 75 minutes (no help)
β Write clean, bug-free code
β Explain time/space complexity
β Discuss alternative approaches
Success Rate Target: 80%+ (8 out of 10 attempts)
For every problem, force yourself to write this:
// 1. Pattern: [name of pattern] // 2. Invariant: [what remains true throughout] // 3. Why O(n): [why this complexity]
Example 1: Two Sum
// 1. Pattern: HashMap for O(1) lookup // 2. Invariant: complement = target - current exists in map when solution found // 3. Why O(n): Single pass, each lookup/insert is O(1)
Example 2: Longest Substring Without Repeating
// 1. Pattern: Sliding window (variable size) + HashSet // 2. Invariant: window [left, right] contains no duplicates // 3. Why O(n): Each character added once (right++) and removed once (left++)
Example 3: Valid Parentheses
// 1. Pattern: Stack for matching pairs // 2. Invariant: Stack always contains unmatched opening brackets // 3. Why O(n): Single pass, each push/pop is O(1)
Problem Given
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Is it about array/string traversal? β
βββββββββββββββββββββββββββββββββββββββββββ€
β β Finding pair/triplet? β
β β Two Pointers (opposite direction) β
β β
β β Contiguous subarray with condition? β
β β Sliding Window β
β β
β β Need to track something for O(1)? β
β β HashMap/HashSet β
βββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Is it about finding next greater/ β
β smaller or matching pairs? β
βββββββββββββββββββββββββββββββββββββββββββ€
β β Next greater/smaller element? β
β β Monotonic Stack β
β β
β β Matching/nesting structure? β
β β Stack β
βββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Is data sorted or can be sorted? β
βββββββββββββββββββββββββββββββββββββββββββ€
β β Search in sorted array? β
β β Binary Search β
β β
β β "Minimum X to achieve Y"? β
β β Answer Binary Search β
βββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Is it about linked list? β
βββββββββββββββββββββββββββββββββββββββββββ€
β β Find middle/cycle? β
β β Fast/Slow Pointer β
β β
β β Reverse/merge? β
β β Pointer Manipulation β
βββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Is it about tree/graph? β
βββββββββββββββββββββββββββββββββββββββββββ€
β β Need depth/paths? β
β β DFS (Recursion) β
β β
β β Need level-by-level? β
β β BFS (Queue) β
β β
β β Dependencies/cycles? β
β β Topological Sort β
βββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Is it optimization problem? β
βββββββββββββββββββββββββββββββββββββββββββ€
β β Can make local optimal choice? β
β β Greedy β
β β
β β Need to consider all possibilities? β
β β Dynamic Programming β
β β
β β Need top K elements? β
β β Heap β
βββββββββββββββββββββββββββββββββββββββββββ
Model Answer:
1. Clarify the problem:
- "Can I assume the array is sorted?"
- "What should I return if input is empty?"
- "Are there any constraints on input size?"
2. Start with brute force:
- "The naive approach would be O(nΒ²) nested loops"
- "But we can optimize using..."
3. Identify pattern:
- "This looks like a two-pointer problem because..."
- "I notice we need to track a window, so sliding window"
4. Explain as you code:
- "I'm using a HashMap here because..."
- "This edge case handles when..."
5. Test with examples:
- Walk through with given example
- Test edge case: empty, single element, duplicates
Model Answer:
Two Pointers:
- Used when we need to compare/process two elements
- Pointers can move in opposite directions (converging)
- Or same direction with different speeds (fast/slow)
- Example: Palindrome check, remove duplicates
Sliding Window:
- Used for contiguous subarrays/substrings
- Window expands (right++) and shrinks (left++)
- Maintains some property within window
- Example: Longest substring, max sum subarray
Key Difference:
- Two pointers: Usually about element relationship
- Sliding window: Always about subarray/substring property
Model Answer:
Use DFS when:
β You need to explore depth (all paths, max depth)
β You need to process nodes top-to-bottom
β Problem involves recursion naturally
β Space constraint (DFS uses O(h), BFS uses O(w))
Examples: Validate BST, Path Sum, Diameter
Use BFS when:
β You need level-by-level processing
β You need to find shortest path
β You need nodes at same level together
Examples: Level Order, Min Depth, Right Side View
Trade-off:
- DFS: O(h) space, harder to reason about levels
- BFS: O(w) space, easier for level-based problems
Model Answer:
Use HashMap when you need:
1. O(1) lookup/insertion
- "Have I seen this element before?"
- Two Sum: "Does complement exist?"
2. Frequency counting
- Group Anagrams, Top K Frequent
- Character count for anagram checking
3. Index tracking
- "Where did I last see this character?"
- Longest Substring Without Repeating
4. Mapping relationships
- Clone Graph: original β clone mapping
- Isomorphic Strings: char β char mapping
Pattern:
If you're writing nested loop to search β Use HashMap
Model Answer:
Time Complexity:
"Let me walk through what happens:
- We iterate through n elements once β O(n)
- For each element, we do constant work β O(1)
- Total: O(n) Γ O(1) = O(n)"
Space Complexity:
"For space, we're using:
- HashMap that stores at most n elements β O(n)
- A few variables (left, right) β O(1)
- Total: O(n) for the HashMap"
Pro Tip:
Always mention:
1. What 'n' represents
2. Why each operation is O(?)
3. Whether you can optimize further
Model Answer:
1. Think out loud:
"I'm thinking about using a HashMap here, but..."
"Let me consider the edge cases first..."
2. Start with brute force:
"I can solve this in O(nΒ²) by..."
"But I think we can optimize to O(n) by..."
3. Ask for hints:
"I'm stuck on handling duplicates. Can you give me a hint?"
"Should I be thinking about sorting first?"
4. Work through an example:
"Let me trace through with [1, 2, 3]..."
"Oh, I see the pattern now!"
5. Discuss trade-offs:
"I could use more space to optimize time..."
"Which would you prefer in production?"
Remember: Interviewers care more about your thought process
than getting the perfect answer immediately.
β BAD Approach:
// Jumped straight into coding without clarification const solve = (arr) => { // Wait, is arr sorted? Can it be empty? // What if there are duplicates? for (let i = 0; i < arr.length; i++) { // I'm not even sure what I'm trying to find... } };
β GOOD Approach:
/** * Before coding, I clarified: * 1. Input: sorted array, can have duplicates * 2. Output: index of first occurrence * 3. Edge: return -1 if not found * 4. Constraints: O(log n) expected β binary search */ const searchFirst = (arr, target) => { let left = 0; let right = arr.length - 1; let result = -1; while (left <= right) { const mid = Math.floor(left + (right - left) / 2); if (arr[mid] === target) { result = mid; // Found, but keep searching left right = mid - 1; // for first occurrence } else if (arr[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return result; };
What goes wrong: Solving the wrong problem, missing edge cases, inefficient approach.
β BAD Approach:
// Remove duplicates from sorted array const removeDuplicates = (nums) => { let j = 0; for (let i = 1; i < nums.length; i++) { if (nums[i] !== nums[j]) { j++; nums[j] = nums[i]; } } return j + 1; // BUG: What if nums is empty? nums.length = 0 // j + 1 = 1, but should return 0! };
β GOOD Approach:
const removeDuplicates = (nums) => { // Handle edge case: empty array if (nums.length === 0) return 0; let j = 0; for (let i = 1; i < nums.length; i++) { if (nums[i] !== nums[j]) { j++; nums[j] = nums[i]; } } return j + 1; }; // Always test with: // 1. Empty: [] // 2. Single element: [1] // 3. All duplicates: [1, 1, 1] // 4. No duplicates: [1, 2, 3]
What goes wrong: Runtime errors, wrong answers for edge cases, failed test cases.
β BAD Approach:
// Find pairs with sum = target (two pointers) const twoSum = (arr, target) => { let left = 0; let right = arr.length - 1; // BUG: Should be left < right, not left <= right while (left <= right) { const sum = arr[left] + arr[right]; if (sum === target) { return [left, right]; } else if (sum < target) { left++; } else { right--; } } return null; }; // When left === right, we're using same element twice! // Example: arr = [2, 3], target = 4 // When left = 0, right = 0 β arr[0] + arr[0] = 4 β Wrong!
β GOOD Approach:
const twoSum = (arr, target) => { let left = 0; let right = arr.length - 1; while (left < right) { // β Correct: ensures different elements const sum = arr[left] + arr[right]; if (sum === target) { return [left, right]; } else if (sum < target) { left++; } else { right--; } } return null; };
What goes wrong: Infinite loops, using same element twice, missing valid pairs.
β BAD Approach:
// Binary search with overflow risk const binarySearch = (arr, target) => { let left = 0; let right = arr.length - 1; while (left <= right) { // BUG: left + right can overflow for large values const mid = Math.floor((left + right) / 2); if (arr[mid] === target) return mid; if (arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; };
β GOOD Approach:
const binarySearch = (arr, target) => { let left = 0; let right = arr.length - 1; while (left <= right) { // β Safe from overflow const mid = Math.floor(left + (right - left) / 2); if (arr[mid] === target) return mid; if (arr[mid] < target) left = mid + 1; else right = mid - 1; } return -1; }; // Why: (left + right) can overflow if left and right are large // But: left + (right - left) / 2 won't overflow
What goes wrong: In languages like Java/C++, overflow causes bugs. Good practice in JavaScript too.
| Operation/Pattern | Time Complexity | Space Complexity | Example |
|---|---|---|---|
| Array traversal | O(n) | O(1) | Single loop |
| Nested loop | O(nΒ²) | O(1) | Find all pairs |
| Binary search | O(log n) | O(1) | Search sorted array |
| HashMap operations | O(1) avg | O(n) | Two Sum |
| Sorting | O(n log n) | O(1) or O(n) | Merge intervals |
| Two pointers | O(n) | O(1) | Palindrome check |
| Sliding window | O(n) | O(k) | Longest substring |
| Stack operations | O(n) | O(n) | Valid parentheses |
| DFS/BFS tree | O(n) | O(h) or O(w) | Tree traversal |
| DFS/BFS graph | O(V + E) | O(V) | Number of islands |
| Heap operations | O(log n) | O(n) | Top K elements |
| Dynamic programming | O(n) to O(nΒ²) | O(n) to O(nΒ²) | Coin change |
Example 1: Two Sum (HashMap)
const twoSum = (nums, target) => { const map = new Map(); // Space: O(n) for (let i = 0; i < nums.length; i++) { // Time: O(n) const complement = target - nums[i]; if (map.has(complement)) { // O(1) return [map.get(complement), i]; } map.set(nums[i], i); // O(1) } return null; }; // Time: O(n) - single loop, O(1) operations inside // Space: O(n) - hashmap stores at most n elements
Example 2: Sliding Window
const longestSubstring = (s) => { const seen = new Set(); // Space: O(min(n, m)) where m = charset size let left = 0; let maxLen = 0; for (let right = 0; right < s.length; right++) { // O(n) while (seen.has(s[right])) { // Inner loop: total O(n) seen.delete(s[left]); left++; } seen.add(s[right]); maxLen = Math.max(maxLen, right - left + 1); } return maxLen; }; // Time: O(n) - each char visited at most twice (right++, left++) // Space: O(min(n, m)) - set stores unique chars
Example 3: DFS Tree
const maxDepth = (root) => { if (!root) return 0; // Base case const left = maxDepth(root.left); // Recursive const right = maxDepth(root.right); // Recursive return Math.max(left, right) + 1; }; // Time: O(n) - visit each node once // Space: O(h) - recursion stack, h = height // O(log n) for balanced tree // O(n) for skewed tree
| Week | Focus | Problems | Key Patterns | Weekend Goal |
|---|---|---|---|---|
| 1 | Arrays + Two Pointers | 12 | Converging, Fast-slow | Create template |
| 2 | Sliding Window + Hashing | 12 | Fixed/variable window | Master window logic |
| 3 | Stack + Monotonic Stack | 10 | Next greater/smaller | Understand monotonic |
| 4 | Binary Search | 11 | Exact + answer search | 2 templates ready |
| 5 | Linked List | 10 | Fast/slow, reversal | No pointer mistakes |
| 6 | Trees DFS/BFS | 12 | Recursion, level order | DFS vs BFS clarity |
| 7 | Heaps + Greedy + Intervals | 11 | Top K, merge intervals | Greedy intuition |
| 8 | Graphs + DP + Mocks | 12 + mocks | DFS/BFS grid, basic DP | 2 mediums in 75 min |
Pattern Over Problems: Master 8 patterns, not 500 problems
Document Everything: Write pattern + invariant + complexity
Spaced Repetition Works: Re-solve after 2 days and 7 days
Time Management: 45-60 mins daily is enough
Interview Skills β Problem Solving: Practice explaining
Progress Formula:
βββββββββββββββββββββββββββββββββββββββββββββ
90 problems Γ Spaced repetition
Γ· 8 weeks
= FAANG interview confidence
βββββββββββββββββββββββββββββββββββββββββββββ
Remember:
β You don't need to be perfect
β You don't need 500 problems
β You need patterns + practice + persistence
Pattern-Based Learning:
Interview Preparation:
Specific Patterns:
Algorithm Fundamentals:
Online Articles & Guides:
Interactive Learning:
Primary Platforms:
Pattern-Focused Practice:
Mock Interviews:
Two Pointers:
Sliding Window:
Binary Search:
Graph Algorithms:
Tracking Progress:
Community:
Test your understanding with 8 quick questions