feat(content): test cases batch 2
This commit is contained in:
@@ -10,18 +10,17 @@ patterns:
|
||||
- binary-search
|
||||
|
||||
description: |
|
||||
Given two sorted arrays `nums1` and `nums2` of size m and n respectively, return the median
|
||||
of the 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)).
|
||||
The overall run time complexity should be **O(log(m+n))**.
|
||||
|
||||
constraints: |
|
||||
- nums1.length == m
|
||||
- nums2.length == n
|
||||
- 0 <= m <= 1000
|
||||
- 0 <= n <= 1000
|
||||
- 1 <= m + n <= 2000
|
||||
- -10^6 <= nums1[i], nums2[i] <= 10^6
|
||||
- `nums1.length == m`
|
||||
- `nums2.length == n`
|
||||
- `0 <= m <= 1000`
|
||||
- `0 <= n <= 1000`
|
||||
- `1 <= m + n <= 2000`
|
||||
- `-10^6 <= nums1[i], nums2[i] <= 10^6`
|
||||
|
||||
examples:
|
||||
- input: "nums1 = [1,3], nums2 = [2]"
|
||||
@@ -32,91 +31,138 @@ examples:
|
||||
explanation: "Merged array is [1,2,3,4]. Median is (2+3)/2 = 2.5."
|
||||
|
||||
explanation:
|
||||
approach: |
|
||||
1. Binary search on the smaller array for partition point
|
||||
2. Partition both arrays such that left half has (m+n+1)//2 elements
|
||||
3. Check if partition is valid: max(left) <= min(right)
|
||||
4. If valid, compute median from boundary elements
|
||||
5. Adjust binary search bounds based on comparison
|
||||
|
||||
intuition: |
|
||||
The median divides the combined array into two halves of equal size. We don't need to
|
||||
actually merge; we just need to find the correct partition.
|
||||
The median divides a sorted array into two equal halves. For two sorted arrays, we need to find a **partition** that puts exactly half the total elements on the left and half on the right.
|
||||
|
||||
If we choose i elements from nums1 for the left half, we need (m+n+1)//2 - i from nums2.
|
||||
Binary search on i (0 to m) to find where nums1[i-1] <= nums2[j] and nums2[j-1] <= nums1[i].
|
||||
Think of it like this: imagine cutting both arrays with vertical lines. If we take `i` elements from `nums1` and `j` elements from `nums2` for the "left half", we need `i + j = (m + n + 1) // 2`. For this partition to be valid:
|
||||
- Everything in the left half ≤ Everything in the right half
|
||||
|
||||
This is O(log min(m,n)) since we binary search on the smaller array.
|
||||
The key insight: once we choose `i` (how many from `nums1`), `j` is determined. So we **binary search on `i`**!
|
||||
|
||||
For a valid partition:
|
||||
- `nums1[i-1] <= nums2[j]` (left of nums1 ≤ right of nums2)
|
||||
- `nums2[j-1] <= nums1[i]` (left of nums2 ≤ right of nums1)
|
||||
|
||||
If not valid, adjust `i`: if `nums1[i-1] > nums2[j]`, we took too many from nums1 — decrease `i`.
|
||||
|
||||
approach: |
|
||||
We solve this using **Binary Search on Partition**:
|
||||
|
||||
**Step 1: Ensure nums1 is the smaller array**
|
||||
|
||||
- If `m > n`, swap the arrays
|
||||
- This guarantees a valid `j` always exists and improves efficiency
|
||||
|
||||
|
||||
|
||||
**Step 2: Binary search for the correct partition**
|
||||
|
||||
- Search for `i` in range `[0, m]` (elements taken from nums1)
|
||||
- Calculate `j = half_len - i` where `half_len = (m + n + 1) // 2`
|
||||
- For each `i`, check if partition is valid
|
||||
|
||||
|
||||
|
||||
**Step 3: Handle boundary cases with infinity**
|
||||
|
||||
- If `i = 0`, there's no left element in nums1 → use `-infinity`
|
||||
- If `i = m`, there's no right element in nums1 → use `+infinity`
|
||||
- Same for `j = 0` and `j = n` in nums2
|
||||
|
||||
|
||||
|
||||
**Step 4: Compute the median**
|
||||
|
||||
- If partition is valid:
|
||||
- **Odd total**: median = `max(left1, left2)`
|
||||
- **Even total**: median = `(max(left1, left2) + min(right1, right2)) / 2`
|
||||
- If not valid, adjust binary search bounds
|
||||
|
||||
|
||||
|
||||
The median is formed by the boundary elements at the valid partition.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Not handling edge cases at partition
|
||||
- title: Not Handling Boundary Cases
|
||||
description: |
|
||||
When partition is at array boundary (i=0 or i=m), use -inf or inf for boundary values.
|
||||
wrong_approach: "Accessing nums1[i-1] when i=0"
|
||||
correct_approach: "Use float('-inf') if i == 0"
|
||||
When `i = 0` or `i = m`, there's no left or right element in nums1. Accessing `nums1[i-1]` or `nums1[i]` would be out of bounds.
|
||||
|
||||
- title: Binary searching on the longer array
|
||||
description: |
|
||||
Always binary search on the shorter array to ensure valid partition exists
|
||||
and for better efficiency.
|
||||
Use `float('-inf')` for missing left elements and `float('inf')` for missing right elements. This ensures comparisons always work correctly.
|
||||
wrong_approach: "Accessing nums1[i-1] when i = 0"
|
||||
correct_approach: "nums1_left = float('-inf') if i == 0 else nums1[i-1]"
|
||||
|
||||
- title: Odd vs even total length
|
||||
- title: Binary Searching on the Longer Array
|
||||
description: |
|
||||
For odd total, median is max of left half.
|
||||
For even, it's average of max(left) and min(right).
|
||||
Always search on the shorter array. If `m > n` and we search on nums1, `j = half_len - i` might become negative (invalid).
|
||||
|
||||
Swapping ensures `j` is always valid: `0 <= j <= n`.
|
||||
wrong_approach: "Binary searching on the longer array"
|
||||
correct_approach: "if m > n: swap arrays, then binary search on the shorter one"
|
||||
|
||||
- title: Odd vs Even Total Length
|
||||
description: |
|
||||
For **odd** total `(m + n)`: the median is a single value — `max(left1, left2)`.
|
||||
For **even** total: the median is the average of two middle values.
|
||||
|
||||
Getting this wrong produces incorrect results for half the test cases.
|
||||
wrong_approach: "Always averaging two values"
|
||||
correct_approach: "Check (m + n) % 2 and handle odd/even separately"
|
||||
|
||||
key_takeaways:
|
||||
- Binary search on partition, not on values
|
||||
- Partition both arrays to have equal halves
|
||||
- Handle boundary conditions with infinity
|
||||
- O(log min(m,n)) is achievable
|
||||
- "**Binary search on partition, not values**: Search for how many elements to take from nums1"
|
||||
- "**Partition both arrays to split total elements in half**: Once we choose `i`, `j` is determined"
|
||||
- "**Handle boundaries with infinity**: Prevents index errors at array edges"
|
||||
- "**O(log min(m,n))**: Binary search on the smaller array is sufficient"
|
||||
|
||||
time_complexity: "O(log min(m,n))"
|
||||
space_complexity: "O(1)"
|
||||
complexity_explanation: |
|
||||
Time: Binary search on the smaller array.
|
||||
Space: Only constant extra variables.
|
||||
time_complexity: "O(log min(m, n)). Binary search on the smaller array."
|
||||
space_complexity: "O(1). Only constant extra variables for pointers and boundary values."
|
||||
|
||||
solutions:
|
||||
- approach_name: Binary Search on Partition (Optimal)
|
||||
- approach_name: Binary Search on Partition
|
||||
is_optimal: true
|
||||
code: |
|
||||
def find_median_sorted_arrays(nums1: list[int], nums2: list[int]) -> float:
|
||||
# Ensure nums1 is the smaller array
|
||||
# Ensure nums1 is the smaller array for valid j values
|
||||
if len(nums1) > len(nums2):
|
||||
nums1, nums2 = nums2, nums1
|
||||
|
||||
m, n = len(nums1), len(nums2)
|
||||
left, right = 0, m
|
||||
half_len = (m + n + 1) // 2
|
||||
half_len = (m + n + 1) // 2 # Size of left half (ceiling for odd total)
|
||||
|
||||
left, right = 0, m # Binary search bounds for i
|
||||
|
||||
while left <= right:
|
||||
i = (left + right) // 2 # Partition in nums1
|
||||
j = half_len - i # Partition in nums2
|
||||
i = (left + right) // 2 # Elements from nums1 in left half
|
||||
j = half_len - i # Elements from nums2 in left half
|
||||
|
||||
# Handle edge cases with infinity
|
||||
# Handle boundary cases with infinity
|
||||
nums1_left = float('-inf') if i == 0 else nums1[i - 1]
|
||||
nums1_right = float('inf') if i == m else nums1[i]
|
||||
nums2_left = float('-inf') if j == 0 else nums2[j - 1]
|
||||
nums2_right = float('inf') if j == n else nums2[j]
|
||||
|
||||
# Check if partition is valid
|
||||
if nums1_left <= nums2_right and nums2_left <= nums1_right:
|
||||
# Found valid partition
|
||||
# Valid partition found — compute median
|
||||
if (m + n) % 2 == 1:
|
||||
# Odd total: median is max of left half
|
||||
return max(nums1_left, nums2_left)
|
||||
else:
|
||||
# Even total: median is average of middle two
|
||||
return (max(nums1_left, nums2_left) +
|
||||
min(nums1_right, nums2_right)) / 2
|
||||
|
||||
elif nums1_left > nums2_right:
|
||||
# Too many elements from nums1 in left half
|
||||
# Too many from nums1, decrease i
|
||||
right = i - 1
|
||||
else:
|
||||
# Too few elements from nums1 in left half
|
||||
# Too few from nums1, increase i
|
||||
left = i + 1
|
||||
|
||||
return 0.0 # Should never reach here
|
||||
return 0.0 # Should never reach here with valid input
|
||||
explanation: |
|
||||
Binary search to find correct partition point in the smaller array.
|
||||
Partition is valid when all left elements <= all right elements.
|
||||
Compute median from the four boundary elements.
|
||||
**Time Complexity:** O(log min(m, n)) — Binary search on the smaller array.
|
||||
|
||||
**Space Complexity:** O(1) — Only constant extra variables.
|
||||
|
||||
We binary search for the correct partition point in the smaller array. A valid partition has all left elements ≤ all right elements. Once found, the median is computed from the four boundary elements: max of left side for odd totals, average of max-left and min-right for even totals.
|
||||
|
||||
Reference in New Issue
Block a user