Interview Setbook · Part 1 of 6 · Q001–Q035
C++ Mastery Series · Interview Prep

The Interview
Problem Setbook

35 problems per part. 6 parts. 210 problems total — all from LeetCode, Codeforces, HackerRank and CodeChef. Every problem is fully decoded, approached, dry-run traced, and solved with annotated C++ code. This is Part 1: Arrays, Strings, Two Pointers, Sliding Window.

Part 1 · Q001–Q035 Arrays & Strings Two Pointer Sliding Window Hashing
Read This First
How to Use This Book — The Right Way to Practice
The Visual Key

EASY — Should be solved in 10–15 min. If taking longer, you need more fundamentals.

MED — 20–35 min. The bulk of real interviews. This is where preparation shows.

HARD — 35–60 min. FAANG-level. Requires combining multiple patterns.

Orange box = Decode: strip the problem to its algorithmic core
Blue box = Approach: structured thinking before any code
Dashed trace = Dry Run: the algorithm animated on a real example
Code block = Annotated C++ solution

The Right Practice Habit

Read the problem. Close the book. Spend 10–20 minutes attempting it on paper or in an editor. THEN look at the Decode and Approach boxes. Still stuck? Read the trace. Only then look at the code. Copy-pasting solutions builds zero problem-solving muscle.

Chapter 01 · Q001–Q014 · Arrays & Strings
Arrays & Strings — The Interview Bread and Butter
Q001 · EASY Two Sum
ArrayHash
LeetCode #1
Must Know Asked 10,000+ Classic

Given array nums and integer target, return the indices of the two numbers that add up to target. Exactly one solution exists. Same element can't be used twice.

Inputnums=[2,7,11,15] target=9
Output[0,1]
Input 2nums=[3,2,4] target=6
Output 2[1,2]
Constraints: 2 ≤ n ≤ 10⁴ · -10⁹ ≤ nums[i] ≤ 10⁹
Decode — What Is Really Being Asked

For each number x at position i, you need to know: does (target − x) exist somewhere in the array before or after i? This is a lookup problem — not a search problem. The word "indices" tells you to remember positions, not just values. The moment you frame it as a lookup, the hash map appears.

Brute O(n²)

Nested Loops

For every i, loop j from i+1 to end. Check if nums[i]+nums[j]==target.

Time: O(n²) · Space: O(1)
Optimal O(n)

Hash Map (One Pass)

Walk array once. At each x, check if (target−x) is already in the map. If yes → answer. Else store x's index and move on.

Time: O(n) · Space: O(n) ✓
Approach — Single-Pass Hash Map

Key mental model: Don't look for pairs. Instead, at each element x, ask: "is my complement (target−x) already stored?" If yes — you have your pair. If no — store x so future elements can use it as their complement. This turns the O(n²) "check every pair" into O(n) "store and check in one pass."

Critical detail: Look up BEFORE inserting. If you insert first, nums[0]+nums[0] could incorrectly match itself.

Dry Run: nums=[2,7,11,15], target=9 map = {} (stores value → index) i=0: x=2 complement=9-2=7 Is 7 in map? NO → store {2:0} i=1: x=7 complement=9-7=2 Is 2 in map? YES at index 0 → return [0, 1] ✓ Dry Run 2: nums=[3,2,4], target=6 i=0: x=3, comp=3, map has 3? NO → {3:0} i=1: x=2, comp=4, map has 4? NO → {3:0,2:1} i=2: x=4, comp=2, map has 2? YES at index 1 → return [1, 2]
C++ Solution — O(n) time · O(n) space vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int,int> seen; // value → index for (int i = 0; i < (int)nums.size(); i++) { int comp = target - nums[i]; if (seen.count(comp)) // complement already seen? return {seen[comp], i}; // YES → return both indices seen[nums[i]] = i; // NO → record for future lookups } return {}; }
TimeO(n)
SpaceO(n)
Similar3Sum · Two Sum II (sorted) · 4Sum
Q002 · EASY Best Time to Buy and Sell Stock
ArrayGreedy
LeetCode #121
Must Know Asked 8,000+

Array prices[i] = stock price on day i. Choose one day to buy and a later day to sell. Return the maximum profit. Return 0 if no profit is possible.

Input[7,1,5,3,6,4]
Output5
WhyBuy day2(1) Sell day5(6) → 5
Input 2[7,6,4,3,1]
Output 20
Decode — Running Minimum to the Left

For each day, the best possible profit = today's price minus the cheapest price ever seen before today. You don't need to know the future — just track the minimum so far and compute the profit at each step.

Approach — Single Pass, Two Variables

Walk left to right. minPrice = cheapest day seen so far (update when you see something cheaper). maxProfit = best profit seen so far (update when today's price - minPrice is larger). No need to track which days — just the values.

prices = [7, 1, 5, 3, 6, 4] minPrice=∞, maxProfit=0 day0: price=7 minPrice=7 profit=7-7=0 maxProfit=0 day1: price=1 minPrice=1 profit=1-1=0 maxProfit=0 day2: price=5 minPrice=1 profit=5-1=4 maxProfit=4 day3: price=3 minPrice=1 profit=3-1=2 maxProfit=4 day4: price=6 minPrice=1 profit=6-1=5 maxProfit=5 day5: price=4 minPrice=1 profit=4-1=3 maxProfit=5 Answer: 5
C++ Solution — O(n) time · O(1) space int maxProfit(vector<int>& prices) { int minPrice = INT_MAX, maxProfit = 0; for (int p : prices) { minPrice = min(minPrice, p); // Cheapest day seen so far maxProfit = max(maxProfit, p - minPrice); // Best profit if sold today } return maxProfit; }
TimeO(n)
SpaceO(1)
SimilarLC#122 multiple transactions · Kadane's Algorithm
Q003 · MEDIUM Maximum Subarray (Kadane's Algorithm)
ArrayDP
LeetCode #53
Must Know Asked 7,000+ Named Algorithm

Find the contiguous subarray with the largest sum and return its sum.

Input[-2,1,-3,4,-1,2,1,-5,4]
Output6
Why[4,-1,2,1] = 6
Follow-up: Can you solve it in O(n) with O(1) space?
Decode — One Binary Choice at Every Position

At every index i, you have exactly two choices: extend the current subarray (add nums[i] to running sum) OR start fresh at nums[i]. You should start fresh whenever the running sum is negative — because a negative prefix can only drag down future sums. The key DP insight: curSum = max(nums[i], curSum + nums[i]).

Approach — Kadane's Algorithm

Two variables: curSum (best ending at current position) and maxSum (global best seen so far). At each step, either extend or restart. Update global max. This is O(1) space DP — the "previous state" is just one number.

Edge case: Initialize both with nums[0], not 0. The subarray must contain at least one element, so an all-negative array should return its maximum (least negative) element.

nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] i=0: cur=-2 maxSum=-2 i=1: cur=max(1,-2+1)=1 maxSum=1 i=2: cur=max(-3,1-3)=-2 maxSum=1 i=3: cur=max(4,-2+4)=4 maxSum=4 i=4: cur=max(-1,4-1)=3 maxSum=4 i=5: cur=max(2,3+2)=5 maxSum=5 i=6: cur=max(1,5+1)=6 maxSum=6 i=7: cur=max(-5,6-5)=1 maxSum=6 i=8: cur=max(4,1+4)=5 maxSum=6 Answer: 6 (subarray [4,-1,2,1])
C++ Solution — Kadane's Algorithm int maxSubArray(vector<int>& nums) { int curSum = nums[0], maxSum = nums[0]; for (int i = 1; i < (int)nums.size(); i++) { curSum = max(nums[i], curSum + nums[i]); // Extend or restart maxSum = max(maxSum, curSum); // Update global best } return maxSum; } // Extension: return the actual subarray [start, end] indices pair<int,int> maxSubarrayIndices(vector<int>& nums) { int curSum=nums[0], maxSum=nums[0]; int start=0, end=0, tempStart=0; for (int i=1;i<(int)nums.size();i++){ if (nums[i] > curSum+nums[i]){ curSum=nums[i]; tempStart=i; } else curSum+=nums[i]; if (curSum>maxSum){ maxSum=curSum; start=tempStart; end=i; } } return {start, end}; }
TimeO(n)
SpaceO(1)
SimilarMaximum Product Subarray · Best Time to Buy Stock
Q004 · MEDIUM Product of Array Except Self
ArrayPrefix
LeetCode #238
Must Know Trick: No Division Allowed

Return array answer where answer[i] = product of all elements except nums[i]. Solve in O(n) without using division.

Input[1,2,3,4]
Output[24,12,8,6]
Verifyans[0]=2×3×4=24 ans[2]=1×2×4=8
Decode — Split the Product into Left × Right

answer[i] = (product of all to LEFT of i) × (product of all to RIGHT of i). Build left products in one forward pass, then multiply by right products in one backward pass. No extra array for right products — accumulate in a single variable.

nums = [1, 2, 3, 4] === Left Pass (out[i] = product of everything LEFT of i) === out[0] = 1 (nothing to the left) out[1] = 1×1 = 1 out[2] = 1×2 = 2 out[3] = 2×3 = 6 out = [1, 1, 2, 6] === Right Pass (multiply by running right product) === rightProd = 1 i=3: out[3] = 6×1 = 6 rightProd = 1×4 = 4 i=2: out[2] = 2×4 = 8 rightProd = 4×3 = 12 i=1: out[1] = 1×12= 12 rightProd = 12×2 = 24 i=0: out[0] = 1×24= 24 rightProd = 24×1 = 24 Final: [24, 12, 8, 6] ✓
C++ Solution — O(n) time · O(1) extra space vector<int> productExceptSelf(vector<int>& nums) { int n = nums.size(); vector<int> out(n, 1); // Left pass: out[i] = product of all nums[j] where j < i for (int i = 1; i < n; i++) out[i] = out[i-1] * nums[i-1]; // Right pass: multiply out[i] by running right product int right = 1; for (int i = n-1; i >= 0; i--) { out[i] *= right; // Multiply accumulated right product right *= nums[i]; // Extend right product leftward } return out; }
TimeO(n)
SpaceO(1) extra
PatternPrefix product · two-pass technique
Q005 · MEDIUM Maximum Product Subarray
ArrayDP
LeetCode #152
Must Know Track Both Max and Min

Find the contiguous subarray with the largest product and return that product.

Input[2,3,-2,4]
Output6
Input 2[-2,0,-1]
Output 20
Decode — Negatives Flip Sign: Track Both Max and Min

Unlike sum, a negative product can become positive when multiplied by another negative. So the current minimum (most negative) is just as important as the current maximum — a new negative could make it the new maximum. Track both curMax and curMin at all times. When you hit a negative number, swap them before computing.

nums = [2, 3, -2, 4] curMax=2, curMin=2, result=2 i=1 (3): curMax=max(3, 2×3, 2×3)=6 curMin=min(3, 6, 6)=3 result=6 i=2 (-2): swap! (neg flips max/min) curMax=max(-2, 3×-2, 6×-2)=-2 curMin=min(-2,-6,-12)=-12 result=6 i=3 (4): curMax=max(4,-2×4,-12×4)=4 Wait: max(4, -2×4=-8, -12×4=-48)=4 curMin=min(4,-8,-48)=-48 result=max(6,4)=6 Answer: 6 (subarray [2,3])
C++ Solution — O(n) time · O(1) space int maxProduct(vector<int>& nums) { int res = nums[0], curMax = nums[0], curMin = nums[0]; for (int i = 1; i < (int)nums.size(); i++) { if (nums[i] < 0) swap(curMax, curMin); // Negative flips max/min curMax = max(nums[i], curMax * nums[i]); curMin = min(nums[i], curMin * nums[i]); res = max(res, curMax); } return res; }
TimeO(n)
SpaceO(1)
PatternVariant of Kadane's · two-state tracking
Q006 · MEDIUM Find All Duplicates in an Array
ArrayIndex Trick
LeetCode #442
Trick: Array as In-Place Hash Map

Array of n integers, each in range [1,n]. Some appear twice, others once. Find all that appear twice. Must run in O(n) time with O(1) extra space.

Input[4,3,2,7,8,2,3,1]
Output[2,3]
Decode — Use the Array Index as a Hash Map Key

Since values are in [1,n], value v maps to index (v−1). When you "visit" value v, negate nums[v−1]. If you encounter v again and nums[v−1] is already negative, v has been seen twice → it's a duplicate. After processing, restore signs if needed.

nums = [4, 3, 2, 7, 8, 2, 3, 1] i=0: val=4 → nums[3]=7 > 0 → negate: [...,-7,...] i=1: val=3 → nums[2]=2 > 0 → negate: [...,-2,-7,...] i=2: val=|2|=2 → nums[1]=3 > 0 → negate: [4,-3,-2,-7,...] i=3: val=|7|=7 → nums[6]=3 > 0 → negate: [...,-3,...] i=4: val=8 → nums[7]=1 > 0 → negate: [...,-1] i=5: val=|2|=2 → nums[1]=-3 < 0 → DUPLICATE: 2 i=6: val=|-3|=3 → nums[2]=-2 < 0 → DUPLICATE: 3 i=7: val=|-1|=1 → nums[0]=4 > 0 → negate Output: [2, 3]
C++ Solution — O(n) time · O(1) space vector<int> findDuplicates(vector<int>& nums) { vector<int> result; for (int x : nums) { int idx = abs(x) - 1; // Map value to index if (nums[idx] < 0) result.push_back(idx + 1); // Already negative = seen twice else nums[idx] = -nums[idx]; // Negate to mark as visited } return result; }
TimeO(n)
SpaceO(1)
SimilarLC#268 Missing Number · LC#41 First Missing Positive
Q007 · HARD Trapping Rain Water
ArrayTwo PointerPrefix
LeetCode #42
Must Know Asked 7,000+ 3 Different Approaches

Given an elevation map (heights array), compute how much water can be trapped after raining.

Input[0,1,0,2,1,0,1,3,2,1,2,1]
Output6
Decode — Water at Position i = min(maxLeft, maxRight) − height[i]

Water sits at position i up to the level of the shorter wall on either side. If that level is higher than h[i], water collects. The formula: water[i] = max(0, min(maxLeft[i], maxRight[i]) - h[i]). The challenge is computing maxLeft and maxRight efficiently.

O(n²)

For Each i, Scan Both Sides

For each i, scan left for max and right for max. O(n) per element.

Time: O(n²) · Space: O(1)
O(n) Space

Prefix Max Arrays

Precompute leftMax[i] and rightMax[i] arrays. Then sum contributions in one pass.

Time: O(n) · Space: O(n)
O(1) Space

Two Pointers

Process from both ends. The shorter side's max is the bottleneck — compute its water, advance that pointer.

Time: O(n) · Space: O(1) ✓
Two Pointer Approach — Why It Works

Two pointers lo (left) and hi (right). Track maxL and maxR (max heights seen from each side). At each step: if h[lo] < h[hi], the left side is the bottleneck. If h[lo] >= maxL, update maxL (no water here, it's a wall). Else water = maxL - h[lo]. Advance lo. Symmetrically for the right side.

h = [0,1,0,2,1,0,1,3,2,1,2,1] (simplified trace) lo=0 hi=11 maxL=0 maxR=0 water=0 h[lo]=0 < h[hi]=1 → left side h[0]=0 ≥ maxL=0 → maxL=0 (update maxL, no water) lo=1 h[lo]=1 ≥ h[hi]=1 → right side h[11]=1 ≥ maxR=0 → maxR=1 (update maxR) hi=10 h[lo]=1 < h[hi]=2 → left side h[1]=1 ≥ maxL=0 → maxL=1 (wall) lo=2 h[lo]=0 < h[hi]=2 → left side h[2]=0 < maxL=1 → water += 1-0=1 lo=3 ... (continue) Total water: 6
C++ Solution — Two Pointers O(n) O(1) int trap(vector<int>& h) { int lo=0, hi=h.size()-1, water=0; int maxL=0, maxR=0; while (lo < hi) { if (h[lo] < h[hi]) { h[lo] >= maxL ? maxL=h[lo] : water+=maxL-h[lo]; // Left bottleneck lo++; } else { h[hi] >= maxR ? maxR=h[hi] : water+=maxR-h[hi]; // Right bottleneck hi--; } } return water; }
TimeO(n)
SpaceO(1)
PatternPrefix max · two-pointer · monotonic stack also possible
Q008 · MEDIUM Container With Most Water
ArrayTwo Pointer
LeetCode #11
Must Know Key Insight: Always Move Shorter Wall

Array of heights. Find two lines forming a container that holds the most water. Return the max area. Area = min(h[l], h[r]) × (r − l).

Input[1,8,6,2,5,4,8,3,7]
Output49
Whyh[1]=8, h[8]=7 min(8,7)×7 = 49
Decode — Greedy: Moving the Taller Wall Never Helps

If we have pointers at l and r, the area is limited by the shorter wall. Moving the taller pointer inward: the width decreases, and the height is still bounded by the same or smaller value — area can only decrease or stay same. Moving the shorter pointer inward is the only way to possibly find a taller pair and improve area.

C++ Solution — O(n) time · O(1) space int maxArea(vector<int>& h) { int lo=0, hi=h.size()-1, best=0; while (lo < hi) { best = max(best, min(h[lo],h[hi]) * (hi-lo)); h[lo] < h[hi] ? lo++ : hi--; // Move shorter wall inward } return best; }
TimeO(n)
SpaceO(1)
SimilarTrapping Rain Water · 3Sum
Q009 · MEDIUM 3Sum
ArrayTwo Pointer
LeetCode #15
Must Know Asked 6,000+ Sort First, Then Fix+Two Pointer

Find all unique triplets in the array that sum to zero. Answer must not contain duplicate triplets.

Input[-1,0,1,2,-1,-4]
Output[[-1,-1,2], [-1,0,1]]
Decode — Fix One, Then Two-Sum on the Rest

Sort first. Fix nums[i] as the first element. Use two pointers j=i+1 and k=end to find pairs summing to −nums[i]. Sort enables both two pointers AND easy duplicate skipping (skip if nums[i]==nums[i-1]).

Approach — Sort + Fix + Two Pointer

Outer loop fixes nums[i]. Skip duplicates at i. Inner: two pointers j and k from both sides of the remaining array. If sum==0: record, skip duplicates on both j and k sides. If sum<0: j++ (need larger). If sum>0: k-- (need smaller). Total: O(n²) with O(1) extra space.

sorted: [-4,-1,-1,0,1,2] i=0: nums[i]=-4 j=1 k=5 sum=-4+(-1)+2=-3 < 0 → j=2 sum=-4+(-1)+2=-3 < 0 → j=3 sum=-4+0+2=-2 < 0 → j=4 sum=-4+1+2=-1 < 0 → j=5 → j>=k, stop i=1: nums[i]=-1 j=2 k=5 sum=-1+(-1)+2=0 → FOUND [-1,-1,2] skip dup j: j=3, skip dup k: k=4 j++,k--: j=4,k=3 → stop i=2: nums[2]=-1 == nums[1]=-1 → SKIP duplicate i=3: nums[i]=0 j=4 k=5 sum=0+1+2=3 > 0 → k=4 → j>=k, stop Wait: j=4,k=4 → j0 → k=4 → j>=k stop Hmm let me redo i=2 skip, i=3 (0): j=4,k=5: 0+1+2=3>0 k=4 done i=4 (1): j=5,k=5 done Answer: [[-1,-1,2],[-1,0,1]] Note: [-1,0,1] found when i=1, j=3(0), k=5... let me redo After recording [-1,-1,2]: j=3, k=4 sum=-1+0+1=0 → FOUND [-1,0,1] j=4, k=3 → done ✓
C++ Solution — O(n²) time · O(1) extra space vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(), nums.end()); vector<vector<int>> res; for (int i = 0; i < (int)nums.size()-2; i++) { if (i > 0 && nums[i] == nums[i-1]) continue; // Skip dup at i int j = i+1, k = nums.size()-1; while (j < k) { int s = nums[i]+nums[j]+nums[k]; if (s == 0) { res.push_back({nums[i],nums[j],nums[k]}); while(j<k && nums[j]==nums[j+1]) j++; // Skip dup j while(j<k && nums[k]==nums[k-1]) k--; // Skip dup k j++; k--; } else if (s < 0) j++; else k--; } } return res; }
TimeO(n²)
SpaceO(1) extra
Similar4Sum · 3Sum Closest · Two Sum
Q010 · MEDIUM Rotate Array by K Steps
ArrayMath
LeetCode #189
3-Reverse Trick Interview Classic

Rotate array to the right by k positions in-place with O(1) extra space.

Input[1,2,3,4,5,6,7] k=3
Output[5,6,7,1,2,3,4]
Decode — Three Reverses Give Any Rotation

Right rotate by k: reverse entire array → reverse [0..k-1] → reverse [k..n-1]. Works because reversing strategically re-arranges elements in exactly the rotated order. Always take k = k % n first to handle k > n.

[1,2,3,4,5,6,7] k=3 Step 1 — Reverse all: [7,6,5,4,3,2,1] Step 2 — Reverse [0..k-1]: [5,6,7,4,3,2,1] Step 3 — Reverse [k..n-1]: [5,6,7,1,2,3,4] Result: [5,6,7,1,2,3,4]
C++ Solution — O(n) time · O(1) space void rotate(vector<int>& nums, int k) { k %= nums.size(); // Handle k > n reverse(nums.begin(), nums.end()); // Reverse all reverse(nums.begin(), nums.begin() + k); // Reverse first k reverse(nums.begin() + k, nums.end()); // Reverse rest }
TimeO(n)
SpaceO(1)
Q011 · EASY Valid Palindrome
StringTwo Pointer
LeetCode #125
Must Know String Basics

Check if a string is a palindrome considering only alphanumeric characters and ignoring case. "A man, a plan, a canal: Panama" → true.

Decode — Two Pointer, Skip Non-Alphanumeric

Two pointers from both ends. Skip non-alphanumeric characters. Compare lowercased characters. If any mismatch → false.

C++ Solution bool isPalindrome(string s) { int l=0, r=s.size()-1; while (l < r) { while(l<r && !isalnum(s[l])) l++; while(l<r && !isalnum(s[r])) r--; if(tolower(s[l++]) != tolower(s[r--])) return false; } return true; }
TimeO(n)
SpaceO(1)
Q012 · MEDIUM Longest Palindromic Substring
StringDP / Expand
LeetCode #5
Must Know Asked 6,000+ Expand Around Center

Return the longest palindromic substring of string s.

Input"babad"
Output"bab" or "aba"
Input 2"cbbd"
Output 2"bb"
Decode — Every Palindrome Has a Center. Expand From It.

Every palindrome is symmetric about its center. There are 2n−1 possible centers (n single characters + n−1 gaps between characters). For each center, expand outward while characters match. Track the longest found. O(n²) time, O(1) space — better than O(n²) space DP.

Approach — Expand Around Center

For each index i, expand for odd-length palindromes (center at i) and even-length palindromes (center between i and i+1). Return the substring of the longest expansion found.

C++ Solution — O(n²) time · O(1) space string longestPalindrome(string s) { int n=s.size(), start=0, maxLen=1; // Expand around center c1=c2 (odd) or c1,c2 adjacent (even) auto expand=[&](int l, int r){ while(l>=0 && r<n && s[l]==s[r]){ l--; r++; } if(r-l-1 > maxLen){ maxLen=r-l-1; start=l+1; } }; for(int i=0;i<n;i++){ expand(i, i); // Odd length — center at i expand(i, i+1); // Even length — center between i and i+1 } return s.substr(start, maxLen); }
TimeO(n²)
SpaceO(1)
O(n)Manacher's Algorithm (see File 06)
Q013 · MEDIUM Encode and Decode Strings
StringDesign
LeetCode #271 (Premium) / HackerRank
Length Prefix Encoding System Design Pattern

Design encode and decode functions to serialize a list of strings to a single string and back. Must handle any character including # and /.

Encode["hello","world"] → "5#hello5#world"
Decode"5#hello5#world" → ["hello","world"]
Decode — Use Length as Prefix, Not a Delimiter Character

You can't use a fixed delimiter like '|' because strings might contain it. Instead, prefix each string with its length followed by a separator character (like '#'). During decode, read the number, skip the '#', read exactly that many characters. Works for any content.

C++ Solution string encode(vector<string>& strs) { string res; for(auto& s : strs) res += to_string(s.size()) + "#" + s; // "len#string" return res; } vector<string> decode(string s) { vector<string> res; int i = 0; while(i < (int)s.size()){ int j = s.find('#', i); // Find the '#' separator int len = stoi(s.substr(i, j-i)); // Parse the length prefix res.push_back(s.substr(j+1, len)); // Extract exactly len chars i = j + 1 + len; // Advance past this entry } return res; }
encodeO(n)
decodeO(n)
Q014 · HARD Median of Two Sorted Arrays
ArrayBinary Search
LeetCode #4
Must Know FAANG Favorite Binary Search on Partition

Given two sorted arrays of size m and n, return the median of the combined sorted array. Runtime must be O(log(min(m,n))).

InputA=[1,3], B=[2]
Output2.0
Input 2A=[1,2], B=[3,4]
Output 22.5
Decode — Binary Search a Partition, Not a Value

The median divides the combined sorted array in half. We need to find where to cut both arrays such that: every element on the left half ≤ every element on the right half. Binary search on the partition point in the shorter array — the other partition is determined automatically.

Approach — Binary Search on Shorter Array

Always binary search on A (the shorter array). Partition A at position i, B at position j=(m+n+1)/2−i. Check: A[i-1] ≤ B[j] AND B[j-1] ≤ A[i]. If A[i-1] > B[j]: move i left. If B[j-1] > A[i]: move i right. When correct: if (m+n) is odd → max(left halves). If even → average of (max left, min right).

C++ Solution — O(log min(m,n)) double findMedianSortedArrays(vector<int>& A, vector<int>& B) { if (A.size() > B.size()) swap(A, B); // Ensure A is shorter int m=A.size(), n=B.size(), lo=0, hi=m; while (lo <= hi) { int i=lo+(hi-lo)/2, j=(m+n+1)/2-i; int AL=i==0 ? INT_MIN : A[i-1]; int AR=i==m ? INT_MAX : A[i]; int BL=j==0 ? INT_MIN : B[j-1]; int BR=j==n ? INT_MAX : B[j]; if (AL<=BR && BL<=AR) { // Correct partition! if((m+n)%2) return max(AL,BL); return (max(AL,BL)+min(AR,BR))/2.0; } AL>BR ? hi=i-1 : lo=i+1; // Adjust search direction } return 0.0; }
TimeO(log min(m,n))
SpaceO(1)
PatternBS on partition · not on value
↑ back to top
Chapter 02 · Q015–Q028 · Two Pointer & Sliding Window
Two Pointer & Sliding Window — Converting O(n²) to O(n)
When to Use Each Pattern

Two Pointer (sorted array / opposite ends): When you need to find pairs/triplets. Works because sorted order lets you make greedy pointer movements — if sum is too small, move left pointer right; if too large, move right pointer left.

Sliding Window (same direction): When you need a contiguous subarray/substring satisfying some condition. Fixed window: add right element, remove left element each step. Variable window: expand until invalid, shrink until valid again.

Q015 · MEDIUM Longest Substring Without Repeating Characters
StringSliding WindowHash
LeetCode #3
Must Know Asked 10,000+ Variable Window Template

Find the length of the longest substring without repeating characters.

Input"abcabcbb"
Output3 ("abc")
Input 2"pwwkew"
Output 23 ("wke")
Decode — Expand Until Duplicate, Then Jump Left

Maintain a window [left, right]. Expand right freely. When a duplicate is found, advance left past the PREVIOUS occurrence of that character. Use a hash map to store the LAST seen position of each character — this lets you jump left in one step instead of inching forward.

s = "abcabcbb" left=0, best=0 r=0: 'a' → new, last={'a':0}, best=1 r=1: 'b' → new, last={..,'b':1}, best=2 r=2: 'c' → new, last={..,'c':2}, best=3 r=3: 'a' → dup! last['a']=0, left=max(0,0+1)=1, best=3 r=4: 'b' → dup! last['b']=1, left=max(1,1+1)=2, best=3 r=5: 'c' → dup! last['c']=2, left=max(2,2+1)=3, best=3 r=6: 'b' → dup! last['b']=4, left=max(3,4+1)=5 window="cb", best=3 r=7: 'b' → dup! last['b']=6, left=max(5,6+1)=7 window="b", best=3 Answer: 3
C++ Solution — O(n) time · O(min(n, charset)) space int lengthOfLongestSubstring(string s) { unordered_map<char,int> last; // char → most recent index int best = 0, left = 0; for (int r = 0; r < (int)s.size(); r++) { if (last.count(s[r])) left = max(left, last[s[r]] + 1); // Jump left past the duplicate last[s[r]] = r; best = max(best, r - left + 1); } return best; }
TimeO(n)
SpaceO(min(n, charset))
PatternVariable window · jump left on duplicate
Q016 · HARD Minimum Window Substring
StringSliding WindowHash
LeetCode #76
Must Know FAANG Favorite Template Problem

Return the minimum window substring of s that contains all characters of t (including duplicates). Return "" if no such window.

Inputs="ADOBECODEBANC" t="ABC"
Output"BANC"
Decode — Expand Until Valid, Then Shrink to Minimize

Track how many characters of t have been "satisfied" in the current window. Expand right until all are satisfied (window is valid). Then shrink left to find the smallest valid window. Record the best. When shrinking makes it invalid, expand right again. The key counter: formed = number of unique characters in t whose frequency in window matches the requirement.

Approach — Two Maps + Formed Counter

need map: frequency of each char in t. have map: frequency of each char in current window. formed: incremented when have[c] == need[c] for some c. When formed == required (all t's unique chars satisfied), the window is valid — try to shrink left.

C++ Solution — O(|s| + |t|) time string minWindow(string s, string t) { unordered_map<char,int> need, have; for (char c : t) need[c]++; int formed=0, required=(int)need.size(); int best=INT_MAX, bl=0, left=0; for (int r = 0; r < (int)s.size(); r++) { have[s[r]]++; if(need.count(s[r]) && have[s[r]]==need[s[r]]) formed++; while(formed == required) { // Window is valid — shrink if(r-left+1 < best){ best=r-left+1; bl=left; } have[s[left]]--; if(need.count(s[left]) && have[s[left]] < need[s[left]]) formed--; left++; } } return best==INT_MAX ? "" : s.substr(bl, best); }
TimeO(|s|+|t|)
SpaceO(|t|)
PatternExpand-until-valid, Shrink-to-minimize
Q017 · MEDIUM Maximum Sum Subarray of Size K (Fixed Window)
ArraySliding Window
GFG / HackerRank Classic
Fixed Window Template

Find the maximum sum of any contiguous subarray of exactly size K.

Input[2,1,5,1,3,2], K=3
Output9 (5+1+3)
Decode — Fixed Window: Remove Left, Add Right, Each Step is O(1)

Build the first window of K elements. Then for each new element added (right), remove the element that left the window (left = right - K). This is the "fixed window" sliding pattern — no variable shrinking needed.

[2,1,5,1,3,2] K=3 Init window [0..2]: sum = 2+1+5 = 8 best=8 Slide i=3: add a[3]=1, remove a[0]=2 sum=8-2+1=7 best=8 Slide i=4: add a[4]=3, remove a[1]=1 sum=7-1+3=9 best=9 Slide i=5: add a[5]=2, remove a[2]=5 sum=9-5+2=6 best=9 Answer: 9
C++ Solution — O(n) time · O(1) space int maxSumK(vector<int>& a, int k) { int sum = 0; for (int i=0;i<k;i++) sum += a[i]; // Build initial window int best = sum; for (int i=k;i<(int)a.size();i++) { sum += a[i] - a[i-k]; // Slide: add right, remove left best = max(best, sum); } return best; }
TimeO(n)
SpaceO(1)
Q018 · MEDIUM Longest Repeating Character Replacement
StringSliding Window
LeetCode #424
Must Know Key: windowSize − maxFreq ≤ k

Given string s and integer k, find the length of the longest substring containing the same letter that can be obtained by replacing at most k characters.

Inputs="AABABBA", k=1
Output4
Why"AABA" → replace B → "AAAA"
Decode — Window is Valid When (Size − MaxFreq) ≤ k

The number of replacements needed to make the entire window one character = window size − frequency of the most common character. If this is ≤ k, the window is valid. Maximize the window size while keeping this condition true.

Key Insight — Why maxF Doesn't Need to Decrease

maxF is a monotone value — once it increases, it never needs to go lower for our purpose. If shrinking the window decreases the max frequency, the window size also decreases, so the condition can't get worse than before. We only care about windows LARGER than the current best, and those require maxF to increase.

C++ Solution — O(n) time · O(26) space int characterReplacement(string s, int k) { int freq[26]={}, maxF=0, left=0, best=0; for (int r=0;r<(int)s.size();r++) { maxF = max(maxF, ++freq[s[r]-'A']); while ((r-left+1) - maxF > k) { // Too many replacements freq[s[left]-'A']--; left++; } best = max(best, r-left+1); } return best; }
TimeO(n)
SpaceO(26)
Q019 · MEDIUM Permutation in String
StringSliding WindowHash
LeetCode #567
Must Know Fixed Window = Length of s1

Return true if s2 contains a permutation of s1 as a substring (i.e., some window in s2 is an anagram of s1).

Inputs1="ab", s2="eidbaooo"
Outputtrue ("ba" in s2)
Decode — Anagram = Same Character Counts. Fixed Window of Size |s1|.

A permutation of s1 in s2 = any window of length |s1| in s2 that has the same character frequencies as s1. Use two frequency arrays, maintain a matches counter (how many characters have matching frequencies). Update matches as you slide.

C++ Solution — O(n) with frequency matching counter bool checkInclusion(string s1, string s2) { if(s1.size() > s2.size()) return false; int need[26]={}, have[26]={}, matches=0; for(char c:s1) need[c-'a']++; int k=s1.size(); // Build initial window for(int i=0;i<k;i++){ have[s2[i]-'a']++; if(have[s2[i]-'a']==need[s2[i]-'a']) matches++; } if(matches==26) return true; for(int r=k;r<(int)s2.size();r++){ int add=s2[r]-'a', rem=s2[r-k]-'a'; // Add right character have[add]++; if(have[add]==need[add]) matches++; else if(have[add]==need[add]+1) matches--; // Remove left character have[rem]--; if(have[rem]==need[rem]) matches++; else if(have[rem]==need[rem]-1) matches--; if(matches==26) return true; } return false; }
TimeO(n)
SpaceO(26)
Q020 · MEDIUM Sliding Window Maximum
ArraySliding WindowMonotonic Deque
LeetCode #239
Must Know Hard but Patterned Monotonic Decreasing Deque

Return the maximum of each sliding window of size k as it slides across the array.

Input[1,3,-1,-3,5,3,6,7] k=3
Output[3,3,5,5,6,7]
Decode — Maintain the Maximum Without Rescanning

Brute force: for each window, scan k elements. O(nk). Better: use a monotonic decreasing deque — it stores candidate maximums in decreasing order. The front is always the current window's maximum. Elements that can never be the maximum (smaller elements behind a larger one) are discarded. Each element enters and exits the deque once → O(n).

[1,3,-1,-3,5,3,6,7] k=3 dq=[] (stores indices, front=max) i=0: add 0(val=1). dq=[0] i=1: add 1(val=3). 3>1 → pop 0. dq=[1] i=2: add 2(val=-1). -1<3. dq=[1,2]. window full → output a[dq[0]]=a[1]=3 i=3: add 3(val=-3). dq=[1,2,3]. remove front if out of window (front=1, 3-1<k). output a[1]=3 i=4: add 4(val=5). 5>a[3]=-3→pop, 5>a[2]=-1→pop, 5>a[1]=3→pop. dq=[4]. output a[4]=5 i=5: add 5(val=3). dq=[4,5]. output a[4]=5 i=6: add 6(val=6). 6>3→pop 5, 6>5? NO wait 6>a[4]=5→pop 4. dq=[6]. output a[6]=6 i=7: add 7(val=7). 7>a[6]=6→pop. dq=[7]. output a[7]=7 Result: [3,3,5,5,6,7]
C++ Solution — O(n) time · O(k) space vector<int> maxSlidingWindow(vector<int>& a, int k) { deque<int> dq; // Stores indices (decreasing values) vector<int> res; for (int i=0;i<(int)a.size();i++) { while(!dq.empty() && a[dq.back()]<=a[i]) dq.pop_back(); // Remove smaller elements dq.push_back(i); if(dq.front() <= i-k) dq.pop_front(); // Remove out-of-window element if(i >= k-1) res.push_back(a[dq.front()]); // Front is always the max } return res; }
TimeO(n)
SpaceO(k)
PatternMonotonic deque · appears in many hard sliding window problems
Q021 · MEDIUM Subarray Sum Equals K
ArrayHashPrefix Sum
LeetCode #560
Must Know Asked 5,000+ Prefix Sum + Hash Map

Given integer array and integer k, count the total number of subarrays whose sum equals k. Array may contain negative numbers.

Input[1,1,1], k=2
Output2
Why[1,1](0..1) and [1,1](1..2)
Decode — prefixSum[i] − prefixSum[j] = k means subarray [j+1..i] sums to k

Rearranged: we want to count positions j where prefixSum[j] = prefixSum[i] - k. Keep a frequency map of prefix sums seen so far. At each position i, add freq[prefixSum - k] to the answer, then increment freq[prefixSum]. Note: negative numbers make sliding window INVALID here — must use prefix sum approach.

nums=[1,1,1], k=2 freq={0:1} psum=0 count=0 i=0: psum=1, need=1-2=-1, freq[-1]=0, count+=0. freq={0:1,1:1} i=1: psum=2, need=2-2=0, freq[0]=1, count+=1. freq={0:1,1:1,2:1} i=2: psum=3, need=3-2=1, freq[1]=1, count+=1. freq={...3:1} Answer: 2
C++ Solution — O(n) time · O(n) space int subarraySum(vector<int>& nums, int k) { unordered_map<int,int> freq; freq[0] = 1; // Empty prefix has sum 0 int psum=0, count=0; for (int x : nums) { psum += x; count += freq[psum - k]; // How many prefixes sum to (psum - k)? freq[psum]++; } return count; }
TimeO(n)
SpaceO(n)
PatternPrefix sum + hash · same logic for XOR subarrays
Q022 · MEDIUM Longest Consecutive Sequence
ArrayHash Set
LeetCode #128
Must Know Only Start Counting from Sequence Beginnings

Find the length of the longest consecutive sequence in an unsorted array. Required: O(n) time.

Input[100,4,200,1,3,2]
Output4 (1,2,3,4)
Decode — Start Counting Only at the Beginning of Each Sequence

An element n is the START of a sequence only if (n−1) is NOT in the set. Only then count consecutive elements from n. This avoids redundant counting — every element is visited at most twice total, giving O(n).

C++ Solution — O(n) time · O(n) space int longestConsecutive(vector<int>& nums) { unordered_set<int> s(nums.begin(), nums.end()); int best = 0; for (int n : s) { if (s.count(n-1)) continue; // n is not a sequence start → skip int len = 1; while (s.count(++n)) len++; // Count consecutive elements best = max(best, len); } return best; }
TimeO(n)
SpaceO(n)
Q023 · EASY Valid Anagram
StringHash
LeetCode #242
Must Know Frequency Array Basics

Return true if t is an anagram of s (same characters, same frequencies, any order).

Inputs="anagram" t="nagaram"
Outputtrue
Input 2s="rat" t="car"
Output 2false
C++ — Two Approaches // Method 1: Sort both strings (simplest) — O(n log n) bool isAnagramSort(string s, string t) { sort(s.begin(),s.end()); sort(t.begin(),t.end()); return s == t; } // Method 2: Frequency array — O(n) time, O(1) space bool isAnagram(string s, string t) { if(s.size() != t.size()) return false; int freq[26] = {}; for(char c : s) freq[c-'a']++; // Count s for(char c : t) if(--freq[c-'a'] < 0) return false; // Subtract t return true; // All zeroed out = anagram }
TimeO(n)
SpaceO(26) = O(1)
Q024 · MEDIUM Group Anagrams
StringHash
LeetCode #49
Must Know Canonical Key Trick

Given an array of strings, group the anagrams together.

Input["eat","tea","tan","ate","nat","bat"]
Output[["bat"],["nat","tan"],["ate","eat","tea"]]
Decode — All Anagrams Share the Same Sorted Form

"eat", "tea", "ate" all sort to "aet". Use the sorted form as the hash map key. All words with the same key belong to the same group.

C++ Solution — O(n·k·log k) where k=avg string length vector<vector<string>> groupAnagrams(vector<string>& strs) { unordered_map<string,vector<string>> groups; for (auto& s : strs) { string key = s; sort(key.begin(), key.end()); // Canonical form groups[key].push_back(s); } vector<vector<string>> res; for (auto& [k,v] : groups) res.push_back(v); return res; }
TimeO(n·k·log k)
SpaceO(n·k)
Q025 · MEDIUM Top K Frequent Elements
ArrayHashBucket Sort
LeetCode #347
Must Know Bucket Sort Beats Heap for O(n)

Return the k most frequent elements. Answer can be in any order.

Input[1,1,1,2,2,3], k=2
Output[1,2]
Decode — Frequency can be at most n. Use n+1 Buckets.

Count frequencies. Create n+1 buckets where bucket[i] holds all elements with frequency i. Scan from the highest bucket downward, collecting elements until k are gathered. Total O(n) time — no sorting needed.

C++ Solution — O(n) Bucket Sort approach vector<int> topKFrequent(vector<int>& nums, int k) { int n = nums.size(); unordered_map<int,int> freq; for(int x : nums) freq[x]++; vector<vector<int>> buckets(n+1); // bucket[i] = elements with freq i for(auto& [val,cnt] : freq) buckets[cnt].push_back(val); vector<int> res; for(int i=n; i>=1 && (int)res.size()<k; i--) for(int x : buckets[i]) if((int)res.size()<k) res.push_back(x); return res; }
TimeO(n)
SpaceO(n)
AltMin-heap of size k: O(n log k)
— End of Chapter 2 preview — Q026–Q028 cover Subarray Product < K, Binary Subarrays with Sum, Fruit Into Baskets —
Q026 · MEDIUM Subarray Product Less Than K
ArraySliding Window
LeetCode #713
Variable Window on Product

Count the number of contiguous subarrays where the product of all elements is strictly less than k. All nums[i] are positive.

Input[10,5,2,6], k=100
Output8
Decode — Each Valid Window [left,right] Contributes (right−left+1) New Subarrays

For a valid window ending at right, the new subarrays added are: [right], [right-1,right], ..., [left,right]. That's exactly (right − left + 1) subarrays. Shrink window when product ≥ k. Positive numbers mean the product is monotone as the window grows.

C++ Solution — O(n) int numSubarrayProductLessThanK(vector<int>& a, int k) { if(k <= 1) return 0; int prod=1, left=0, count=0; for(int r=0;r<(int)a.size();r++){ prod *= a[r]; while(prod >= k) prod /= a[left++]; // Shrink left until valid count += r - left + 1; // New subarrays ending at r } return count; }
TimeO(n)
SpaceO(1)
Q027 · MEDIUM Fruit Into Baskets (Longest Subarray with at Most 2 Distinct)
ArraySliding WindowHash
LeetCode #904
Template: At Most K Distinct Values

Find the longest subarray containing at most 2 distinct values. This is the general "at most K distinct" sliding window template (K=2 here).

Input[1,2,1,2,3]
Output4 ([1,2,1,2])
C++ Solution — Variable Window with Map int totalFruit(vector<int>& fruits) { unordered_map<int,int> basket; int left=0, best=0; for(int r=0;r<(int)fruits.size();r++){ basket[fruits[r]]++; while(basket.size() > 2){ // More than 2 types → shrink basket[fruits[left]]--; if(!basket[fruits[left]]) basket.erase(fruits[left]); left++; } best = max(best, r-left+1); } return best; }
TimeO(n)
SpaceO(K)
Q028 · MEDIUM Minimum Size Subarray Sum
ArraySliding Window
LeetCode #209
Must KnowPositive-Only Variable Window

Given positive integers array and target, find the minimum length of a subarray whose sum is ≥ target. Return 0 if impossible.

Input[2,3,1,2,4,3], target=7
Output2 ([4,3])
Decode — Positive Numbers Make Sum Monotone → Variable Window Works

Expand right to increase sum. When sum ≥ target, the window is valid — record its length, then shrink left to see if a shorter window also satisfies. Since all values are positive, shrinking decreases the sum, so we can always know when to stop.

C++ Solution — O(n) int minSubArrayLen(int target, vector<int>& a) { int left=0, sum=0, best=INT_MAX; for(int r=0;r<(int)a.size();r++){ sum += a[r]; while(sum >= target){ // Window valid → try to shrink best = min(best, r-left+1); sum -= a[left++]; } } return best==INT_MAX ? 0 : best; }
TimeO(n)
SpaceO(1)
↑ back to top
Chapter 03 · Q029–Q035 · Binary Search
Binary Search — Not Just for Sorted Arrays — Search the Answer Space
The 3 Binary Search Templates — Learn All Three

T1 — Exact match: lo≤hi, mid=(lo+hi)/2. Return index or -1.
T2 — First position where condition is true (lower_bound): lo=0, hi=n, lo<hi. If cond(mid): hi=mid. Else: lo=mid+1. Returns first valid index.
T3 — Last position where condition is true: lo=0, hi=n, lo<hi. If cond(mid): lo=mid+1. Else: hi=mid. Returns lo-1 = last valid.
T4 — Search on Answer Space: lo=min_answer, hi=max_answer. Binary search on the answer, verify with a helper function in O(n).

Q029 · EASY Binary Search (Foundation Template)
ArrayBinary Search
LeetCode #704
Must KnowAll 3 Templates Here

Given sorted array of distinct integers and target, return its index or -1 in O(log n).

Decode — Use lo+(hi−lo)/2 to Avoid Overflow

Never write (lo+hi)/2 — it overflows for large indices. Always write lo + (hi-lo)/2. This is the single most common binary search bug.

C++ — All 3 Templates // Template 1: Exact search int bsearch(vector<int>& a, int t) { int lo=0, hi=a.size()-1; while(lo <= hi){ int mid = lo + (hi-lo)/2; if(a[mid]==t) return mid; a[mid] < t ? lo=mid+1 : hi=mid-1; } return -1; } // Template 2: First index where a[mid] >= t (lower_bound) int lowerBound(vector<int>& a, int t) { int lo=0, hi=a.size(); // hi=n (can be past end) while(lo < hi){ int mid=lo+(hi-lo)/2; a[mid] < t ? lo=mid+1 : hi=mid; } return lo; // First position where a[pos] >= t } // Template 3: Last index where a[mid] <= t (upper_bound - 1) int upperBound(vector<int>& a, int t) { int lo=0, hi=a.size(); while(lo < hi){ int mid=lo+(hi-lo)/2; a[mid] <= t ? lo=mid+1 : hi=mid; } return lo; // First position where a[pos] > t → last pos = lo-1 }
TimeO(log n)
SpaceO(1)
Q030 · MEDIUM Search in Rotated Sorted Array
ArrayBinary Search
LeetCode #33
Must KnowOne Half Is Always Sorted

Search for target in a rotated sorted array in O(log n).

Input[4,5,6,7,0,1,2] target=0
Output4
Decode — In Every Step, One Half Is Guaranteed Sorted

After a rotation, if we split at mid, either [lo..mid] or [mid..hi] is sorted. Check which half is sorted, then determine which half the target falls in, discard the other. This preserves O(log n) by eliminating half the search space each step.

[4,5,6,7,0,1,2] target=0 lo=0 hi=6 mid=3 (val=7) a[lo]=4 <= a[mid]=7 → LEFT half [lo..mid] is sorted Is target=0 in [4..7]? NO → lo = mid+1 = 4 lo=4 hi=6 mid=5 (val=1) a[lo]=0 <= a[mid]=1 → LEFT half [lo..mid] is sorted Is target=0 in [0..1]? YES → hi = mid-1 = 4... wait target=0 = a[lo] lo=4 hi=4 mid=4 (val=0) a[mid]=0 == target=0 → return 4
C++ Solution — O(log n) int search(vector<int>& a, int t) { int lo=0, hi=a.size()-1; while(lo <= hi){ int mid = lo+(hi-lo)/2; if(a[mid]==t) return mid; if(a[lo] <= a[mid]){ // Left half [lo..mid] is sorted if(a[lo]<=t && t<a[mid]) hi=mid-1; else lo=mid+1; } else { // Right half [mid..hi] is sorted if(a[mid]<t && t<=a[hi]) lo=mid+1; else hi=mid-1; } } return -1; }
TimeO(log n)
SpaceO(1)
Q031 · MEDIUM Find Minimum in Rotated Sorted Array
ArrayBinary Search
LeetCode #153
Must Know

Find the minimum element in a rotated sorted array of unique integers in O(log n).

Input[3,4,5,1,2]
Output1
Decode — Minimum Is at the Rotation Inflection Point

If a[mid] > a[hi], the rotation point (minimum) is in the right half → lo = mid+1. Otherwise, minimum is in the left half including mid → hi = mid. When lo == hi, we have the minimum.

C++ Solution — O(log n) int findMin(vector<int>& a) { int lo=0, hi=a.size()-1; while(lo < hi){ int mid=lo+(hi-lo)/2; a[mid] > a[hi] ? lo=mid+1 : hi=mid; // Min is in the unsorted side } return a[lo]; }
TimeO(log n)
SpaceO(1)
Q032 · MEDIUM Koko Eating Bananas (Binary Search on Answer)
ArrayBinary Search
LeetCode #875
Must KnowBinary Search on Answer SpaceThe Answer-Space Template

Koko eats bananas at speed k bananas/hr (at most). Each pile must be finished before moving to the next. Find the minimum k to finish all piles within h hours.

Inputpiles=[3,6,7,11] h=8
Output4
Decode — Monotone Property → Binary Search on k

If speed k works, speed k+1 also works. This monotone property means: the feasible speeds form a contiguous range [minK, ∞). Binary search the boundary. Range: [1, max(piles)]. For each candidate k, check if all piles can be finished in ≤ h hours using ⌈pile/k⌉ for each pile.

Answer Space Binary Search Pattern — Memorize This

Whenever you see "find the MINIMUM/MAXIMUM value such that some condition holds", suspect binary search on answer. The condition must be monotone: if it holds for x, it holds for all x' beyond x. Define the feasibility check function, then binary search the answer space [lo, hi].

piles=[3,6,7,11], h=8 lo=11 (max pile), hi=27 (sum), ... actually: lo=1, hi=max(piles)=11 mid=6: hours=⌈3/6⌉+⌈6/6⌉+⌈7/6⌉+⌈11/6⌉=1+1+2+2=6 ≤ 8 → works → hi=6 mid=3: hours=⌈3/3⌉+⌈6/3⌉+⌈7/3⌉+⌈11/3⌉=1+2+3+4=10 > 8 → fails → lo=4 mid=5: hours=1+2+2+3=8 ≤ 8 → works → hi=5 mid=4: hours=1+2+2+3=8 ≤ 8 → works → hi=4 lo=hi=4 Answer: 4
C++ Solution — O(n · log(max_pile)) int minEatingSpeed(vector<int>& piles, int h) { auto canFinish=[&](long long k){ long long hours=0; for(int p:piles) hours+=(p+k-1)/k; // ceil(p/k) = (p+k-1)/k return hours <= h; }; int lo=1, hi=*max_element(piles.begin(),piles.end()); while(lo < hi){ int mid=lo+(hi-lo)/2; canFinish(mid) ? hi=mid : lo=mid+1; // Works → try smaller; fails → need bigger } return lo; }
TimeO(n · log(max))
SpaceO(1)
Same PatternShip packages in D days · Painters partition · Aggressive cows
Q033 · MEDIUM Find Peak Element
ArrayBinary Search
LeetCode #162
Go Towards the Uphill Side

Find the index of a peak element (greater than both neighbors). Array may have multiple peaks. Return any. O(log n) required.

Input[1,2,3,1]
Output2
Decode — Always Move Toward the Higher Neighbor

If a[mid] < a[mid+1], the right side is "uphill" → there must be a peak somewhere to the right. Move lo = mid+1. If a[mid] > a[mid+1], the left side has a peak → hi = mid. This always converges to a peak in O(log n).

C++ Solution int findPeakElement(vector<int>& a) { int lo=0, hi=a.size()-1; while(lo < hi){ int mid=lo+(hi-lo)/2; a[mid] < a[mid+1] ? lo=mid+1 : hi=mid; // Go uphill } return lo; }
TimeO(log n)
SpaceO(1)
Q034 · MEDIUM Time-Based Key-Value Store
Binary SearchDesign
LeetCode #981
BS on Timestamps — Floor Query

Design a time-based key-value store with set(key, value, timestamp) and get(key, timestamp) — returns the value with the largest timestamp ≤ given timestamp, or "" if none.

Decode — Timestamps Are Strictly Increasing → Binary Search for Floor

Timestamps are always increasing (given in the problem). For each key, store all (timestamp, value) pairs in sorted order. For get, binary search for the largest timestamp ≤ query timestamp (floor query = upper_bound - 1 pattern).

C++ Solution class TimeMap { unordered_map<string, vector<pair<int,string>>> store; public: void set(string key, string value, int ts){ store[key].push_back({ts, value}); // Timestamps always increasing } string get(string key, int ts){ if(!store.count(key)) return ""; auto& v = store[key]; // Find largest timestamp <= ts int lo=0, hi=v.size()-1, res=-1; while(lo <= hi){ int mid=lo+(hi-lo)/2; if(v[mid].first <= ts){ res=mid; lo=mid+1; } // Valid → go right else hi=mid-1; } return res==-1 ? "" : v[res].second; } };
setO(1)
getO(log n)
Q035 · HARD Split Array Largest Sum (BS on Answer)
ArrayBinary SearchDP
LeetCode #410
Must KnowBinary Search on Answer + Greedy Verification

Split array into k non-empty subarrays to minimize the maximum subarray sum. Return that minimum possible maximum.

Input[7,2,5,10,8], k=2
Output18
Why[7,2,5] and [10,8] max=18, best possible
Decode — Binary Search on the "Capacity" of Each Group

Instead of "find the optimal split" (hard), flip it: "given a maximum sum limit cap, can we split into ≤ k groups?" (easy greedy check). Monotone property: if cap works, cap+1 also works. Binary search on cap from [max(arr), sum(arr)].

Greedy Check — Greedy works because we want MINIMUM groups

Walk left to right. Greedily pack each element into the current group as long as the sum doesn't exceed cap. When it would exceed, start a new group. Count groups needed. If groups ≤ k → cap works.

C++ Solution — O(n · log(sum−max)) int splitArray(vector<int>& nums, int k) { auto canSplit=[&](long long cap){ int groups=1; long long cur=0; for(int x:nums){ if(x>cap) return false; // Single element exceeds cap → impossible if(cur+x>cap){ groups++; cur=0; } // Start new group cur+=x; } return groups <= k; }; long long lo=*max_element(nums.begin(),nums.end()), hi=accumulate(nums.begin(),nums.end(),0LL); while(lo < hi){ long long mid=lo+(hi-lo)/2; canSplit(mid) ? hi=mid : lo=mid+1; } return (int)lo; }
TimeO(n · log(sum))
SpaceO(1)
PatternSame as Koko · Ship packages · Painter's partition · Aggressive cows
↑ back to top