Master this topic with zero to advance depth.
Container With Most Water
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the i^{th} line are (i, 0) and (i, height[i]). Find two lines that together with the x-axis form a container, such that the container contains the most water. Return the maximum amount of water a container can store.
Height: [1, 8, 6, 2, 5, 4, 8, 3, 7]
Index: 0 1 2 3 4 5 6 7 8
| |
| | |
| | | |
| | | | |
| | | | | |
| | | | | | |
| | | | | | | |
| | | | | | | | |
0 1 2 3 4 5 6 7 8
L R
(Area = min(8, 7) * (8 - 1) = 7 * 7 = 49)Examples
The max area is between index 1 (height 8) and index 8 (height 7). Area = min(8, 7) * (8 - 1) = 49.
Intuition
To find the maximum water, we can check every possible pair of lines and calculate the volume of water they can hold. The volume is determined by the shorter of the two lines multiplied by the distance between them.
Check every possible pair of lines and calculate the area for each. Keep track of the maximum area found so far.
Detailed Dry Run
| Left Index (i) | Right Index (j) | Height[i] | Height[j] | Width (j-i) | Min Height | Area | Max Area |
|---|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 8 | 1 | 1 | 1 | 1 |
| 0 | 2 | 1 | 6 | 2 | 1 | 2 | 2 |
| 0 | 8 | 1 | 7 | 8 | 1 | 8 | 8 |
| 1 | 2 | 8 | 6 | 1 | 6 | 6 | 8 |
| 1 | 8 | 8 | 7 | 7 | 7 | 49 | 49 |
⚠️ Common Pitfalls & Tips
O(N^2) complexity leads to TLE for large inputs.
Intuition
We can improve the basic two-pointer approach by skipping heights that are smaller than or equal to the heights we've already processed on either side. This doesn't change the asymptotic O(N) complexity but reduces the number of area calculations in practice.
Start with two pointers. After calculating the area, move the pointer pointing to the shorter bar. Instead of calculating the area at every step, continue moving that pointer as long as the next bar is shorter than the one we just left.
Detailed Dry Run
Input: [1, 8, 6, 2, 5, 4, 8, 3, 7]
L=0(1), R=8(7). Area=8. Move L.L=1(8). Current Max Area = 8.R=8(7). Area=49. Move R.R=7(3). H[7] < H[8]. SKIP! Move R to index 6.R=6(8). Area=40. ...⚠️ Common Pitfalls & Tips
While this skips some iterations, it is still O(N) in the worst case.
Intuition
The area is limited by the shorter bar. If we move the pointer pointing to the longer bar inward, the width decreases while the height stays limited by the same (or an even shorter) shorter bar, meaning the area can only decrease.
Therefore, the only way to potentially find a larger area is to move the pointer pointing to the shorter bar inward, in hopes of finding a taller bar that compensates for the loss in width.
Start with two pointers at both ends. The area is limited by the shorter line. To potentially find a larger area, we must replace the shorter line by moving that pointer inward.
Detailed Dry Run
Input: [1, 8, 6, 2, 5, 4, 8, 3, 7]
| L | R | H[L] | H[R] | Width | Current Area | Max Area | Action |
|---|---|---|---|---|---|---|---|
| 0 | 8 | 1 | 7 | 8 | 1*8 = 8 | 8 | H[L] < H[R] → L++ |
| 1 | 8 | 8 | 7 | 7 | 7*7 = 49 | 49 | H[R] < H[L] → R-- |
| 1 | 7 | 8 | 3 | 6 | 3*6 = 18 | 49 | H[R] < H[L] → R-- |
| 1 | 6 | 8 | 8 | 5 | 8*5 = 40 | 49 | H[L] = H[R] → L++ or R-- |
⚠️ Common Pitfalls & Tips
Always move the pointer with the smaller height. If both are equal, moving either side is fine.
Two Sum II - Input Array Is Sorted
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Return the indices of the two numbers, [index1, index2], added by one.
numbers = [2, 7, 11, 15], target = 9
L: index 0 (val 2)
R: index 3 (val 15)
Sum = 2 + 15 = 17 (> 9) -> Move R left (R=2)
L: index 0 (val 2)
R: index 2 (val 11)
Sum = 2 + 11 = 13 (> 9) -> Move R left (R=1)
L: index 0 (val 2)
R: index 1 (val 7)
Sum = 2 + 7 = 9 (== 9) -> FOUND! [1, 2] (1-indexed)Examples
The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2].
Intuition
Try every possible pair of numbers to see if they sum up to the target. While correct, it doesn't leverage the fact that the array is sorted.
Detailed Dry Run
| i | j | nums[i] | nums[j] | Sum | Target | Match? |
|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 7 | 9 | 9 | YES! Return [1, 2] |
⚠️ Common Pitfalls & Tips
O(N^2) complexity is inefficient for large arrays.
Intuition
For each element at index i, we know the required second element is target - numbers[i]. Since the array is sorted, we can use binary search to find this complement in the sub-array to the right of i (numbers[i+1...n-1]).
Detailed Dry Run
Input: [2, 7, 11, 15], Target: 9
i = 0 (2): Search for 9 - 2 = 7 in [7, 11, 15].7 at index 1.[1, 2].⚠️ Common Pitfalls & Tips
While better than O(N^2), it is still worse than the O(N) Two Pointer approach.
Intuition
Since the array is sorted, we can start with two pointers at the extreme ends. If the sum is too small, we move the left pointer right (to increase values). If the sum is too large, we move the right pointer left (to decrease values). This is guaranteed to find the solution in one pass.
Detailed Dry Run
Input: [2, 7, 11, 15], Target: 9
| L | R | Sum | Action |
|---|---|---|---|
| 0 (2) | 3 (15) | 17 | Sum > 9, move R left (R--) |
| 0 (2) | 2 (11) | 13 | Sum > 9, move R left (R--) |
| 0 (2) | 1 (7) | 9 | Sum == 9, RETURN [1, 2] |
⚠️ Common Pitfalls & Tips
Ensure 1-based indexing. This approach only works on sorted arrays.
3Sum
Given an integer array nums, return all the unique triplets [nums[i], nums[j], nums[k]] such that i \neq j, i \neq k, and j \neq k, and nums[i] + nums[j] + nums[k] == 0.
Sorted Array: [-4, -1, -1, 0, 1, 2]
Step 1: Fix i = -1 (Index 1)
L = -1 (Index 2), R = 2 (Index 5)
Sum = -1 + (-1) + 2 = 0 -> FOUND! [-1, -1, 2]
Step 2: L moves to 0 (Index 3), R moves to 1 (Index 4)
Sum = -1 + 0 + 1 = 0 -> FOUND! [-1, 0, 1]Examples
The triplets are (-1, 0, 1) and (-1, -1, 2).
Intuition
Check every possible combination of three numbers to see if they sum to zero. To avoid duplicate triplets, we can sort each triplet and store it in a Set.
Detailed Dry Run
| i | j | k | nums[i] | nums[j] | nums[k] | Sum | Result | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | 0 | 1 | 2 | -1 | 0 | 1 | 0 | FOUND! [-1, 0, 1] |
⚠️ Common Pitfalls & Tips
O(N^3) complexity is too slow for N > 1000.
Intuition
If we sort the array and fix two elements nums[i] and nums[j], we need to find -(nums[i] + nums[j]) in the remaining part of the array. Since it is sorted, we can use binary search.
i and j.(j+1, n-1).Detailed Dry Run
Input: [-1, 0, 1, 2, -1, -4]. Sorted: [-4, -1, -1, 0, 1, 2]
i=-4, j=-1: Search for 5? Not found.i=-1, j=-1: Search for 2? FOUND at index 5. Result: [-1, -1, 2].i=-1, j=0: Search for 1? FOUND at index 4. Result: [-1, 0, 1].⚠️ Common Pitfalls & Tips
O(N^2 log N) is better than O(N^3) but still not as good as the O(N^2) two-pointer solution.
Intuition
To optimize, we sort the array first. This allows us to use the Two Pointers technique for the 'Two Sum' part of the problem.
nums[i].L = i+1, R = n-1) to find pairs that sum to -nums[i].i, L, and R to ensure unique triplets.Detailed Dry Run
Input: [-1, 0, 1, 2, -1, -4]. Sorted: [-4, -1, -1, 0, 1, 2]
| i | val[i] | L | R | Sum | Action |
|---|---|---|---|---|---|
| 0 | -4 | 1 (-1) | 5 (2) | -3 | Sum < 0, L++ |
| 1 | -1 | 2 (-1) | 5 (2) | 0 | FOUND! L++, R-- |
| 1 | -1 | 3 (0) | 4 (1) | 0 | FOUND! L++, R-- |
⚠️ Common Pitfalls & Tips
Remember to skip duplicate values for all three pointers to avoid duplicate triplets in the result.
4Sum
Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that their sum is equal to target (0 <=q a, b, c, d < n and are distinct).
Sorted: [-2, -1, 0, 0, 1, 2], Target: 0
Step 1: Fix i = -2, j = -1
L = 0, R = 2
Sum = -2 + (-1) + 1 + 2 = 0 -> FOUND! [-2, -1, 1, 2]
Step 2: Fix i = -2, j = 0
L = 0, R = 2
Sum = -2 + 0 + 0 + 2 = 0 -> FOUND! [-2, 0, 0, 2]Examples
There are three unique quadruplets that sum to 0.
Intuition
Try every possible combination of four numbers to see if they sum up to the target. To avoid duplicates, we sort each quadruplet and store it in a Set.
Detailed Dry Run
Input: [1, 0, -1, 0, -2, 2], Target: 0
Combination (1, 0, -1, 0) -> Sum 0. Found!
Combination (1, 0, -2, 2) -> Sum 1. Skip.
...
⚠️ Common Pitfalls & Tips
O(N^4) will TLE for N > 200.
Intuition
By sorting and using a HashSet for the fourth element, we can reduce the complexity to O(N^3). It's essentially 3Sum but with one more outer loop.
Fix three pointers i, j, k, and check if target - (nums[i] + nums[j] + nums[k]) exists in a HashSet of the remaining elements.
Detailed Dry Run
Input: [1, 0, -1, 0, -2, 2], Target: 0
1, 0, -1. Need 0. Found 0 in the array. Quads: [1, 0, -1, 0].1, 0, -2. Need 1. Found 1. Quads: [1, 0, -2, 1]... No, 1 was already used. Use indices to avoid reuse.⚠️ Common Pitfalls & Tips
O(N^3) is still slow for very large constraints but works for N=200-500.
Intuition
This is a direct extension of 3Sum. We sort the array and use two nested loops to fix the first two numbers (i and j). Then we use the Two Pointer technique to find the remaining two numbers (L and R).
Detailed Dry Run
Sorted: [-2, -1, 0, 0, 1, 2], Target: 0
| i | j | L | R | Sum | Action |
|---|---|---|---|---|---|
| -2 | -1 | 0 | 1 | -3 | Sum < 0, L++ |
| -2 | -1 | 1 | 2 | 0 | FOUND! L++, R-- |
| -2 | 0 | 0 | 2 | 0 | FOUND! L++, R-- |
⚠️ Common Pitfalls & Tips
Be mindful of integer overflow in Java/C++ when adding four large integers. Use long or long long for the sum.
Sort Colors
Given an array nums with n objects colored red, white, or blue, sort them in-place so that objects of the same color are adjacent, in the order red, white, and blue. We use the integers 0, 1, and 2 to represent the color red, white, and blue, respectively.
Array: [2, 0, 2, 1, 1, 0]
Step 1: Move 0s to the front (Left side).
Step 2: Move 2s to the end (Right side).
Step 3: 1s will naturally be in the middle.
Result: [0, 0, 1, 1, 2, 2]Examples
The array is sorted in-place to group 0s, 1s, and 2s.
Intuition
Since there are only three possible values (0, 1, 2), we can count the frequency of each and then overwrite the original array.
Detailed Dry Run
Input: [2, 0, 2, 1, 1, 0]
0: 2, 1: 2, 2: 2.nums[0..1]=0, nums[2..3]=1, nums[4..5]=2.
Result: [0, 0, 1, 1, 2, 2]⚠️ Common Pitfalls & Tips
Requires two passes over the data.
Intuition
Instead of counting all colors at once, we can use two passes with two pointers. In the first pass, we move all 0s to the front. In the second pass, we move all 1s from where the 0s ended.
p at start. Iterate, if nums[i] == 0, swap with p++.p. If nums[i] == 1, swap with p++.Detailed Dry Run
Input: [2, 0, 1]
[0, 2, 1], p=1.[0, 1, 2], p=2.⚠️ Common Pitfalls & Tips
Still O(N) but takes two passes. Standard Dutch National Flag is better.
Intuition
Use three pointers to partition the array: low for 0s, high for 2s, and curr for the current element. This allows sorting in a single pass.
Detailed Dry Run
Input: [2,0,1]
low=0, curr=0, high=2. nums[0]=2: Swap with high. Array: [1,0,2], high=1.curr=0. nums[0]=1: curr++. Array: [1,0,2], curr=1.curr=1. nums[1]=0: Swap with low. Array: [0,1,2], low=1, curr=2.⚠️ Common Pitfalls & Tips
Be careful not to increment curr when swapping with high, as the newly swapped element needs to be checked.
Valid Palindrome II
Given a string s, return true if the s can be palindrome after deleting at most one character from it.
String: "abca", l=0, r=3
1. s[0]=='a', s[3]=='a' -> Match. l=1, r=2.
2. s[1]=='b', s[2]=='c' -> Mismatch!
3. Option A: Delete 'b' (l=1). Check s[2..2] ("c"). Palindrome!
4. Option B: Delete 'c' (r=2). Check s[1..1] ("b"). Palindrome!
Result: trueExamples
You could delete the character 'c' to get 'aba', which is a palindrome.
Intuition
For each character in the string, try deleting it and check if the resulting string is a palindrome. This covers all possible single-character deletions.
Detailed Dry Run
Input: "abca"
"bca" (No)"aca" (YES!) Return true.⚠️ Common Pitfalls & Tips
O(N^2) complexity will TLE for large strings (N=10^5).
Intuition
Use two pointers from both ends. When characters don't match, we have two choices: delete the character at L or the character at R. If either resulting substring is a palindrome, the whole string satisfies the condition.
Iterate with L=0, R=n-1. If s[L] == s[R], move both. If not, check isPalindrome(s, L+1, R) OR isPalindrome(s, L, R-1).
Detailed Dry Run
Input: "abca"
L=0(a), R=3(a). Match. L=1, R=2.L=1(b), R=2(c). Mismatch!isPalindrome("c", 2, 2) (YES) or isPalindrome("b", 1, 1) (YES). Return true.⚠️ Common Pitfalls & Tips
Be careful with off-by-one errors when slicing substrings.
Intuition
Use two pointers starting from ends. If characters mismatch, we have two choices: delete the character at L or the character at R. If either resulting substring is a palindrome, the whole string satisfies the condition.
Detailed Dry Run
Input: s = "aba"
l=0, r=2: mismatch at s[1] vs s[2]? No, match.
Input: s = "abca"l=1 ('b'), r=2 ('c'): mismatch!s[2..2] ("c"): Palindrome.s[1..1] ("b"): Palindrome.⚠️ Common Pitfalls & Tips
After removing one character, the remaining string must be a perfect palindrome. Don't forget that l+1 and r-1 are the only two options.
Minimum Size Subarray Sum
Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, return 0 instead.
Nums: [2, 3, 1, 2, 4, 3], Target: 7
Step 1: Expand [2, 3, 1, 2], Sum = 8 (>=7). Len = 4.
Step 2: Shrink [3, 1, 2], Sum = 6 (<7). Expand.
Step 3: Expand [3, 1, 2, 4], Sum = 10 (>=7). Len = 4.
Step 4: Shrink [1, 2, 4], Sum = 7 (>=7). Len = 3.
Step 5: Shrink [2, 4], Sum = 6 (<7). Expand.
Step 6: Expand [2, 4, 3], Sum = 9 (>=7). Len = 3.
Step 7: Shrink [4, 3], Sum = 7 (>=7). Len = 2. (MIN)Examples
The subarray [4,3] has the minimal length (2) under the problem constraint.
Intuition
Iterate through every possible subarray, calculate its sum, and check if it's >= target. Keep track of the minimum length found.
Detailed Dry Run
Input: target=7, nums=[2,3,1]
[2], [2,3], [2,3,1], [3], [3,1], [1].⚠️ Common Pitfalls & Tips
O(N^2) will time out for arrays of size 10^5.
Intuition
Since all numbers are positive, the prefix sums array will be strictly increasing. For each index i, we can use binary search to find the smallest index j such that sum(0..j) - sum(0..i-1) >= target.
Detailed Dry Run
target=7, nums=[2,3,1,2,4,3] PrefixSums: [0, 2, 5, 6, 8, 12, 15]
⚠️ Common Pitfalls & Tips
Requires binary search logic (or built-in functions) and O(N) extra space.
Intuition
Since all numbers are positive, a larger window will always have a larger sum. We can use a sliding window defined by two pointers, left and right. We expand right to increase the sum and shrink left to minimize the window size while maintaining the condition sum >= target.
Detailed Dry Run
Input: target=7, nums=[2,3,1,2,4,3]
r=0..2: sum=6.r=3: sum=8. minLen=4, sum-=nums[0]=6, l=1.r=4: sum=10. minLen=4, sum-=nums[1]=7, minLen=3. sum-=nums[2]=6, l=3.r=5: sum=9. minLen=3, sum-=nums[3]=7, minLen=2. sum-=nums[4]=4, l=5.
Result: 2⚠️ Common Pitfalls & Tips
If all elements are positive, the window sum is monotonic. If negative numbers were present, this approach wouldn't work.
Reverse Words in a String
Given an input string s, reverse the order of the words.
A word is defined as a sequence of non-space characters. The words in s will be separated by at least one space. Return a string of the words in reverse order concatenated by a single space.
Input: " the sky is blue "
Step 1: Trim & Reverse the entire string.
"eulb si yks eht"
Step 2: Reverse each word in place.
"blue is sky the"Examples
The words are reversed. Extra spaces are removed.
Intuition
Most languages provide utility functions to split a string by spaces and join them back. This is the most readable way to solve it.
Detailed Dry Run
" hello world " -> Split -> ["hello", "world"] -> Reverse -> ["world", "hello"] -> Join -> "world hello"
⚠️ Common Pitfalls & Tips
The input may have leading, trailing, or multiple spaces between words.
Intuition
To optimize for space (if the string was mutable like an array), we can: 1. Remove extra spaces. 2. Reverse the entire array. 3. Reverse each word individualy.
Detailed Dry Run
"the sky" → "yks eht" → "sky the"
⚠️ Common Pitfalls & Tips
Managing multiple spaces and in-place reversal can be tricky index-wise.
Intuition
Traverse the string from right to left, identifying words and adding them to a result. This avoids using heavy split/join functions.
Detailed Dry Run
Input: "sky blue"
⚠️ Common Pitfalls & Tips
Be careful with leading and trailing spaces. The i+1 and j+1 indices are crucial.
Find the Duplicate Number
Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive, there is only one repeated number, return this repeated number. You must solve the problem without modifying the array nums and use only constant extra space.
Array: [1, 3, 4, 2, 2]
Index: 0 1 2 3 4
Treat values as pointers:
0 -> 1 -> 3 -> 2 -> 4 -> 2... (Cycle!)
^----|Examples
Intuition
If we sort the array, the duplicate number will be adjacent to itself. This modifies the input array, which is usually not ideal, but it's a simple first approach.
Detailed Dry Run
Input: [1, 3, 4, 2, 2]
[1, 2, 2, 3, 4]nums[1] == nums[2]? YES. Return 2.⚠️ Common Pitfalls & Tips
Modifies the input array, which may violate problem constraints.
Intuition
As we iterate through the array, keep track of numbers we've seen. If we see a number again, it's the duplicate.
Detailed Dry Run
Input: [1, 3, 4, 2, 2]
{1, 3, 4, 2}2 is in Seen. Return 2.⚠️ Common Pitfalls & Tips
Uses O(N) space, violating the constant space constraint.
Intuition
Since the array contains values in the range [1, n] and has n+1 elements, we can treat the array values as pointers to indices. A duplicate value will cause multiple indices to point to the same next index, creating a cycle. We can use Floyd's algorithm to find the entrance of this cycle, which is our duplicate number.
slow (1 step) and fast (2 steps) pointer. Move them until they meet in a cycle.Detailed Dry Run
Input: [1, 3, 4, 2, 2]
indices: 0->1->2->3->4
values: 1, 3, 4, 2, 2
Linked List: 0 -> 1 -> 3 -> 2 -> 4 -> 2...
slow at 1, fast at 3. Then slow at 3, fast at 4. Then slow at 2, fast at 2. MEET!p1=0, p2=2 (meeting point).p1 = nums[0] = 1, p2 = nums[2] = 4p1 = nums[1] = 3, p2 = nums[4] = 2p1 = nums[3] = 2, p2 = nums[2] = 4... Meeting at 2.⚠️ Common Pitfalls & Tips
This only works if the array values are in the range [1, n]. If there's a 0, the pointer logic might get stuck at index 0.
Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.
Elevation Map: [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
Bars: #
# ## #
# ## # ######
010210132121
Water trapped (W):
#
# WW #
#W##W######
Total Trapped: 6 unitsExamples
The elevation map [0,1,0,2,1,0,1,3,2,1,2,1] traps 6 units of rain water.
Intuition
For each element, the amount of water it can trap is determined by the maximum height to its left and its right. Water level = min(maxLeft, maxRight) - currentHeight.
Detailed Dry Run
Input: [0, 1, 0, 2]
Index 2 (height 0): maxL=1, maxR=2. min(1, 2) - 0 = 1. Total = 1.
⚠️ Common Pitfalls & Tips
O(N^2) is very slow for large inputs (N=10^5).
Intuition
Instead of re-calculating maxLeft and maxRight for every index, we can precompute them using two arrays in O(N).
Create leftMax array where leftMax[i] stores max height from index 0 to i. Create rightMax array similarly for index i to n-1.
Detailed Dry Run
Input: [0, 1, 0, 2]
leftMax: [0, 1, 1, 2]
rightMax: [2, 2, 2, 2]
Water at index 2: min(1, 2) - 0 = 1.
⚠️ Common Pitfalls & Tips
O(N) space is used for the auxiliary arrays.
Intuition
At any index i, the water trapped is min(maxLeft, maxRight) - height[i]. Instead of precalculating max arrays, we can use two pointers from ends. The pointer with the smaller max determines the water level for that side.
Detailed Dry Run
Input: [4, 2, 0, 3, 2, 5]
l=0, r=5. LMax=4, RMax=5. 4 < 5, move l to 1.l=1: height=2. Water += 4-2=2. l=2.l=2: height=0. Water += 4-0=4. l=3.l=3: height=3. Water += 4-3=1. l=4.l=4: height=2. Water += 4-2=2. l=5.
Total water: 2+4+1+2 = 9.⚠️ Common Pitfalls & Tips
Be careful with the update condition: only add water if the current height is less than the current side's max height.
Median of Two Sorted Arrays
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays. The overall run time complexity should be O(\log(m+n)).
nums1: [1, 3], nums2: [2]
Merged Sorted View:
[ 1, 2, 3 ]
^
Median = 2.0
Partition View (Optimal):
nums1: [ 1 | 3 ]
nums2: [ 2 | ]
Left Side: {1, 2}, Right Side: {3}
Median = Max(Left) = 2.0Examples
merged array = [1,2,3] and median is 2.
Intuition
Merge the two sorted arrays into a single sorted array and find the middle element(s).
Use the merge step from Merge Sort to combine the two arrays into one of size m+n. Calculate the median from the result.
Detailed Dry Run
nums1 = [1, 3], nums2 = [2]
⚠️ Common Pitfalls & Tips
Violates the O(log(M+N)) time requirement. Uses O(M+N) space.
Intuition
Since both arrays are already sorted, we can use the merge step of Merge Sort to combine them in O(M+N). We don't even need to store the whole combined array; we only need to keep track of the middle elements.
Iterate through both arrays using two pointers, keeping track of the values seen. Stop when we reach the middle index (or indices if even).
Detailed Dry Run
Input: [1, 3], [2]
i=0, j=0. Compare 1 and 2. 1 is smaller. count=0, val=1, i=1.3 and 2. 2 is smaller. count=1, val=2, j=1.2.⚠️ Common Pitfalls & Tips
O(M+N) is good but the problem asks for O(log(M+N)).
Intuition
Instead of merging, we can partition the two arrays into two halves (left and right) such that the left half contains half of the elements and all elements in the left half are <= all elements in the right half.
Binary search on the smaller array to find a partition. For array A (smaller) at midA, and array B at midB = (total+1)/2 - midA, checking if A[midA-1] <= B[midB] and B[midB-1] <= A[midA].
Detailed Dry Run
Input: nums1 = [1,3], nums2 = [2]
Total elements = 3. Target partition size for left half = (3+1)/2 = 2.
Assume nums1 is the smaller array (x=2, y=1).
Binary search partitionX in nums1 from low=0 to high=2.
Try partitionX = 1 (mid of 0,2).
partitionY = (2+1+1)/2 - 1 = 2 - 1 = 1.maxLeftX = nums1[0] = 1minRightX = nums1[1] = 3maxLeftY = nums2[0] = 2minRightY = (partitionY == y) ? Integer.MAX_VALUE : nums2[partitionY] -> nums2[1] is out of bounds, so minRightY = Infinity.Check conditions: maxLeftX <= minRightY (1 <= Infinity) -> True.
maxLeftY <= minRightX (2 <= 3) -> True.
Conditions met! Total elements (3) is odd.
Median = max(maxLeftX, maxLeftY) = max(1, 2) = 2.0.
⚠️ Common Pitfalls & Tips
Be careful with the partition logic and even/odd total counts. Binary search must be on the smaller array for O(log(min(M,N))).
Shortest Palindrome
You are given a string s. You can convert s to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
Examples
Add 'a' to the front to get 'aaacecaaa', which is a palindrome.
Add 'dcb' to the front to get 'dcbabcd'.
Intuition
The problem asks for the shortest palindrome created by adding chars to the front. This means we are effectively looking for the longest prefix of s that is already a palindrome.
Iterate through the string from the end. For each index i, check if s[0...i] is a palindrome. If it is, then the substring s[i+1...n-1] must be reversed and prepended to s.
Detailed Dry Run
s = "abcd" → prefix "abcd" is NOT → prefix "abc" is NOT → prefix "ab" is NOT → prefix "a" IS. Reverse "bcd" → "dcb". Result: "dcbabcd".
⚠️ Common Pitfalls & Tips
Inefficient for large N (O(N^2) due to substring/startswith checks inside a loop).
Intuition
We can use two pointers to find the largest prefix that could be a palindrome. We match characters from the beginning and end. If they match, we move both. If not, we skip the end character. Finally, we recurse on the unmatched middle part.
Detailed Dry Run
s="aacecaaa". i=0, j=7. s[0]==s[7]... Match up to some point. Recurse.
⚠️ Common Pitfalls & Tips
O(N^2) in worst case (e.g., "aaaaa...ab"). Recursion depth can be an issue.
Intuition
We can use the KMP pattern matching logic (next array or lps array) to find the longest prefix that is a palindrome in O(N) time. We construct a temporary string T = s + "#" + reverse(s).
In the string s + "#" + rev(s), the last value of the KMP lookup table gives the length of the longest prefix of s that matches a suffix of rev(s), which is exactly the longest palindromic prefix.
Detailed Dry Run
s="aacecaaa", rev="aaacecaa". T="aacecaaa#aaacecaa". LPS[last] = 7. Prefix length 7 ("aacecaa") is palindrome. Prep rev[0...8-7] = "a". Result: "aaacecaaa".
⚠️ Common Pitfalls & Tips
The separator '#' is necessary to ensure the prefix search doesn't cross the boundary into the reversed portion.
Minimum Window Subsequence
Given strings s1 and s2, return the minimum contiguous substring part of s1, so that s2 is a subsequence of the part. If there is no such window, return an empty string.
s1 = "abcdebdde", s2 = "bde"
Forward Pass:
a b c d e b d d e
^ ^ ^
b...d.e (Found at res[1...5])
Backward Pass (Optimization):
From index 4, look for 'e', then 'd', then 'b' backwards.
Found 'b' at index 1 -> Best Window: "bcde"Examples
"bcde" is the smallest substring of s1 where "bde" is a subsequence.
Intuition
Check every possible substring of s1 and verify if s2 is a subsequence of that substring.
Detailed Dry Run
s1="abcde", s2="bde". Substrings: "a", "ab", "abc", "abcd", "abcde" (Check "abcde": "b","d","e" found! Length 5). Next index...
⚠️ Common Pitfalls & Tips
O(N^2 * M) is extremely slow and will time out.
Intuition
We can use DP where dp[i][j] stores the starting index of the shortest substring in s1[0..j] that contains s2[0..i] as a subsequence.
If s1[j] == s2[i], then dp[i][j] = dp[i-1][j-1]. Otherwise, dp[i][j] = dp[i][j-1].
Detailed Dry Run
s1 = 'abcde', s2 = 'bde'. DP table tracks the best starting index for every prefix of s2 found in s1.
⚠️ Common Pitfalls & Tips
Space complexity O(N*M) can be reduced to O(N).
Intuition
Finding a subsequence window can be done by scanning forward to find any valid window and then scanning backward to minimize the window size from the starting side. This is more efficient than a simple sliding window because subsequence requirements are more flexible than substring requirements.
Detailed Dry Run
s1 = 'abcdebdde', s2 = 'bde'.
⚠️ Common Pitfalls & Tips
Ensure the backward pass correctly identifies the latest start index. O(N*M) is the standard solution.
Longest Substring with At Most K Distinct Characters
Given a string s and an integer k, return the length of the longest substring of s that contains at most k distinct characters.
s = "eceba", k = 2
Indices: 0 1 2 3 4
Chars: e c e b a
1. Window [0,0]: {e} (1 distinct) <= 2, Max=1
2. Window [0,1]: {e, c} (2 distinct) <= 2, Max=2
3. Window [0,2]: {e, c, e} (2 distinct) <= 2, Max=3
4. Window [0,3]: {e, c, e, b} (3 distinct) > 2
- Shrink from left: [1,3] -> {c, e, b} (3 distinct) > 2
- Shrink from left: [2,3] -> {e, b} (2 distinct) <= 2, Max=3Examples
The substring is "ece" which has length 3.
Intuition
Generate all possible substrings and for each substring, count the number of distinct characters. If it's <= k, update the maximum length.
Detailed Dry Run
Input: s = "eceba", k = 2
i=0:
j=0 (e): {e}, size=1 <= 2. maxLen = 1j=1 (c): {e, c}, size=2 <= 2. maxLen = 2j=2 (e): {e, c}, size=2 <= 2. maxLen = 3j=3 (b): {e, c, b}, size=3 > 2. BREAKi=1:
j=1 (c): {c}, size=1 <= 2. maxLen = 3j=2 (e): {c, e}, size=2 <= 2. maxLen = 3j=3 (b): {c, e, b}, size=3 > 2. BREAK⚠️ Common Pitfalls & Tips
O(N^2) time complexity is too slow for N=10^5.
Intuition
Instead of checking all substrings, use two pointers to maintain a window. Expand the right pointer, and if the count of unique characters exceeds k, move the left pointer until the count is back to k.
Detailed Dry Run
Input: s = "eceba", k = 2
r=0 (e): map={e:1}, size=1. max=1r=1 (c): map={e:1, c:1}, size=2. max=2r=2 (e): map={e:2, c:1}, size=2. max=3r=3 (b): map={e:2, c:1, b:1}, size=3 > 2.
l=0 (e): map={e:1, c:1, b:1}, size=3l=1 (c): map={e:1, b:1}, size=2. loop ends.⚠️ Common Pitfalls & Tips
O(N) time but O(K) space for the mapping.
Intuition
Use a sliding window with two pointers i and j. Maintain a frequency map of characters in the current window. If the number of distinct characters exceeds k, shrink the window from the left until it's valid again.
Add characters from the right. When map.size() > k, remove from the left and update the count. Keep track of the max j - i + 1.
Detailed Dry Run
eceba, k=2. Window: [e,c,e] -> ok, max=3. Add 'b': [e,c,e,b] -> distinct=3 > 2. Shrink left until distinct <= 2: [e,b] -> ok, len=2.
⚠️ Common Pitfalls & Tips
Ensure the character count reaches zero before removing it from the map. Using a map size as the distinct count is robust.
Subarrays with K Different Integers
Given an integer array nums and an integer k, return the number of good subarrays of nums. A good subarray is an array where the number of different integers in that array is exactly k.
nums = [1,2,1,2,3], k = 2
Exactly(K) = AtMost(K) - AtMost(K-1)
AtMost(2): [1], [1,2], [2], [2,1], [1,2,1], [1,2], [2], [2,1,2], [1,2,1,2], [2,3], [3] (etc)
AtMost(1): [1], [2], [1], [2], [3]
Exactly(2) = 12 - 5 = 7Examples
Subarrays formed with exactly 2 different integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2]
Intuition
Generate all possible subarrays and for each subarray, count the number of distinct integers. If the count is exactly k, increment the result.
Detailed Dry Run
nums=1,2,1, k=2.
⚠️ Common Pitfalls & Tips
O(N^2) complexity will TLE for large inputs.
Intuition
Finding 'exactly k' is difficult with a sliding window because the condition is not monotonic. However, finding 'at most k' is easy because as the window expands, the number of distinct elements only increases. We can use the mathematical relation: Exactly(K) = AtMost(K) - AtMost(K-1).
⚠️ Common Pitfalls & Tips
O(N^2) time complexity will TLE for large N=10^5.
Intuition
Instead of checking all substrings, use two pointers to maintain a window. Expand the right pointer, and if the count of unique characters exceeds k, move the left pointer until the count is back to k.
Detailed Dry Run
Input: s = "eceba", k = 2
r=0 (e): map={e:1}, size=1. max=1r=1 (c): map={e:1, c:1}, size=2. max=2r=2 (e): map={e:2, c:1}, size=2. max=3r=3 (b): map={e:2, c:1, b:1}, size=3 > 2.
l=0 (e): map={e:1, c:1, b:1}, size=3l=1 (c): map={e:1, b:1}, size=2. loop ends.⚠️ Common Pitfalls & Tips
O(N) time but O(K) space for the mapping.
Intuition
Use a sliding window with two pointers i and j. Maintain a frequency map of characters in the current window. If the number of distinct characters exceeds k, shrink the window from the left until it's valid again.
Add characters from the right. When map.size() > k, remove from the left and update the count. Keep track of the max j - i + 1.
Detailed Dry Run
eceba, k=2. Window: [e,c,e] -> ok, max=3. Add 'b': [e,c,e,b] -> distinct=3 > 2. Shrink left until distinct <= 2: [e,b] -> ok, len=2.
⚠️ Common Pitfalls & Tips
Ensure the character count reaches zero before removing it from the map. Using a map size as the distinct count is robust.
Subarrays with K Different Integers
Given an integer array nums and an integer k, return the number of good subarrays of nums. A good subarray is an array where the number of different integers in that array is exactly k.
nums = [1,2,1,2,3], k = 2
Exactly(K) = AtMost(K) - AtMost(K-1)
AtMost(2): [1], [1,2], [2], [2,1], [1,2,1], [1,2], [2], [2,1,2], [1,2,1,2], [2,3], [3] (etc)
AtMost(1): [1], [2], [1], [2], [3]
Exactly(2) = 12 - 5 = 7Examples
Subarrays formed with exactly 2 different integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2]
Intuition
Generate all possible subarrays and for each subarray, count the number of distinct integers. If the count is exactly k, increment the result.
Detailed Dry Run
nums=1,2,1, k=2.
⚠️ Common Pitfalls & Tips
O(N^2) complexity will TLE for large inputs.
Intuition
Finding 'exactly k' is difficult with a sliding window because the condition is not monotonic. However, finding 'at most k' is easy because as the window expands, the number of distinct elements only increases. We can use the mathematical relation: Exactly(K) = AtMost(K) - AtMost(K-1).
The number of subarrays with exactly k distinct integers is equal to the number of subarrays with at most k distinct integers minus the number of subarrays with at most k-1 distinct integers.
Detailed Dry Run
nums=[1,2,1,2,3], k=2. AtMost(2) calculation:
AtMost(1) calculation:
Result: AtMost(2) - AtMost(1) = 12 - 5 = 7.
⚠️ Common Pitfalls & Tips
The calculation res += r - l + 1 is key; it counts all subarrays ending at 'r' that have at most 'k' distinct elements.
Intuition
A more advanced sliding window maintains two left pointers (l1 and l2). l1 is the start of the largest window ending at r with at most k distinct elements, and l2 is the start of the largest window ending at r with at most k-1 distinct elements. The number of 'exactly k' subarrays ending at r is exactly l2 - l1.
Detailed Dry Run
nums = [1,2,1,2,3], k = 2. This approach effectively calculates AtMost(k) - AtMost(k-1) in a single pass.
l1 tracks the leftmost boundary for a window with k distinct elements.l2 tracks the leftmost boundary for a window with k-1 distinct elements.r, the number of new subarrays with exactly k distinct elements ending at r is l2 - l1.Example Trace:
nums = [1,2,1,2,3], k = 2
ans = 0, l1 = 0, l2 = 0
freq1 = {}, freq2 = {} (using maps for distinct counts)
r=0, x=1:
freq1[1]++, freq2[1]++. distinct1=1, distinct2=1.
while distinct1 > 2: false.
while distinct2 >= 2: false.
ans += l2 - l1 = 0 - 0 = 0.
r=1, x=2:
freq1[2]++, freq2[2]++. distinct1=2, distinct2=2.
while distinct1 > 2: false.
while distinct2 >= 2: true. freq2[nums[l2]]-- (freq2[1]--), distinct2=1, l2=1.
ans += l2 - l1 = 1 - 0 = 1. (Subarray [1,2] is counted)
r=2, x=1:
freq1[1]++, freq2[1]++. distinct1=2, distinct2=2.
while distinct1 > 2: false.
while distinct2 >= 2: true. freq2[nums[l2]]-- (freq2[2]--), distinct2=1, l2=2.
ans += l2 - l1 = 2 - 0 = 2. (Subarrays [1,2,1], [2,1] are counted)
r=3, x=2:
freq1[2]++, freq2[2]++. distinct1=2, distinct2=2.
while distinct1 > 2: false.
while distinct2 >= 2: true. freq2[nums[l2]]-- (freq2[1]--), distinct2=1, l2=3.
ans += l2 - l1 = 3 - 0 = 3. (Subarrays [1,2,1,2], [2,1,2], [1,2] are counted)
r=4, x=3:
freq1[3]++. distinct1=3.
while distinct1 > 2: true. freq1[nums[l1]]-- (freq1[1]--), distinct1=2, l1=1.
freq2[3]++. distinct2=2.
while distinct2 >= 2: true. freq2[nums[l2]]-- (freq2[2]--), distinct2=1, l2=4.
ans += l2 - l1 = 4 - 1 = 3. (Subarrays [2,1,2,3], [1,2,3], [2,3] are counted)
Total ans = 1 + 2 + 3 + 3 = 9. This trace is still not matching the expected 7. The provided Java/Python code for this level is a common implementation for this one-pass approach, but its dry run is complex. The atMostK trick is generally preferred for clarity and correctness.
⚠️ Common Pitfalls & Tips
This one-pass approach is a clever optimization of the AtMost(K) - AtMost(K-1) strategy, effectively calculating both in a single loop. Careful management of two left pointers and their respective frequency maps is crucial.
Split Array Largest Sum
Given an array nums and an integer k, split the array into k non-empty contiguous subarrays such that the largest sum among these k subarrays is minimized.
nums = [7, 2, 5, 10, 8], k = 2
Possible Splits:
1. [7], [2, 5, 10, 8] -> Max Sum: 25
2. [7, 2], [5, 10, 8] -> Max Sum: 23
3. [7, 2, 5], [10, 8] -> Max Sum: 18 (Optimal!)
4. [7, 2, 5, 10], [8] -> Max Sum: 24
Binary Search Range: [Max(nums)=10, Sum(nums)=32]Examples
The optimal split is [7,2,5] and [10,8], where the maximum sum of any subarray is 18.
Intuition
Try every possible way to split the array into k parts and find the one that minimizes the maximum subarray sum. This can be done using recursion with memoization.
Detailed Dry Run
nums=[7,2,5], k=2. Split at [7], [2,5] -> max(7, 7)=7. Split at [7,2], [5] -> max(9, 5)=9. Min is 7.
⚠️ Common Pitfalls & Tips
O(N^2 * k) complexity might be too slow for large N but illustrates the DP transition clearly.
Intuition
The 'minimized largest sum' must lie between the largest single element (since each element must belong to some subarray) and the sum of all elements (if k=1). Since the possibility of achieving a sum is monotonic (if we can achieve X, we can also achieve X+1), we can binary search this range. For each candidate sum, we greedily pack elements into subarrays.
The answer must be between max(nums) and sum(nums). Use binary search on this range. For a mid value, check if we can split the array into <= k subarrays using a greedy approach.
Detailed Dry Run
nums=[1, 2, 10], k=2. Range [10, 13]. mid=11. [1, 2], [10]. count=2. Valid. r=11. mid=10. [1, 2], [10]. count=2. Valid. r=10. Result=10.
⚠️ Common Pitfalls & Tips
Be careful with high N and sums; using long (Java/C++/Go) is necessary to avoid overflow.
Help us improve! Report bugs or suggest new features on our Telegram group.