Given two sorted arrays a and b of size m and n respectively. Find the kth element of the final sorted array.
Input: a = [2, 3, 6, 7, 9], b = [1, 4, 8, 10], k = 5
Output: 6
Explanation: The final sorted array would be [1, 2, 3, 4, 6, 7, 8, 9, 10]. The 5th element of this array is 6.
Input: a = [100, 112, 256, 349, 770], b = [72, 86, 113, 119, 265, 445, 892], k = 7
Output: 256
Explanation: Final sorted array is - [72, 86, 100, 112, 113, 119, 256, 265, 349, 445, 770, 892], 7th element of this array is 256.
Input: a = [2, 3, 6], b = [7, 9], k = 4
The idea here is to use the binary search algorithm to solve this problem in an optimal way. Upon observation, it can be found that this problem is a slight variation of another problem Median of two sorted arrays. So, the entire logic of the optimal solution will remain the same here with just few changes; instead of finding the median, the kth element of two sorted arrays will be determined.
Observation: Assume, m = size of arr1[] and n = size of arr2[]. The median creates a partition on the final merged array, dividing it into two halves with approximately equal sizes, around (m+n) / 2. It was also discussed that these halves must be unique in a valid merged array. The approach involved forming the correct unique left half, assuming it contains x elements from arr1[] and ((m+n)/2)-x elements from arr2[], where x ranges from 0 to min(m, n). For each value in this range, the configuration of the left half was validated using the condition l1 <= r2 && l2 <= r1, where l1, r1 are variables referring to elements from arr1[], and l2, r2 refer to elements from arr2[].
The same approach will be used with some minor changes in the values. The changes will be as follows:
The size of the left half will be k: Here, the median does not need to be found; instead, the k-th element is sought. Therefore, the partition will be placed after the k-th element. Consequently, the size of the left half will be k instead of (m+n)/2. For example,
Note: The answer will always be max(l1, l2) as the kth element will be the maximum element of the left half.
The rest of the process will be as similar to the one used in the problem, Median of 2 sorted arrays.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int kthElement(vector<int>& a, vector<int>& b, int k) {
int m = a.size();
int n = b.size();
// Ensure a is smaller array for optimization
if (m > n) {
// Swap a and b
return kthElement(b, a, k);
}
// Length of the left half
int left = k;
// Apply binary search
int low = max(0, k - n), high = min(k, m);
while (low <= high) {
int mid1 = (low + high) >> 1;
int mid2 = left - mid1;
// Initialize l1, l2, r1, r2
int l1 = (mid1 > 0) ? a[mid1 - 1] : INT_MIN;
int l2 = (mid2 > 0) ? b[mid2 - 1] : INT_MIN;
int r1 = (mid1 < m) ? a[mid1] : INT_MAX;
int r2 = (mid2 < n) ? b[mid2] : INT_MAX;
// Check if we have found the answer
if (l1 <= r2 && l2 <= r1) {
return max(l1, l2);
}
else if (l1 > r2) {
// Eliminate the right half
high = mid1 - 1;
}
else {
// Eliminate the left half
low = mid1 + 1;
}
}
// Dummy return statement
return -1;
}
};
int main() {
vector<int> a = {2, 3, 6, 7, 9};
vector<int> b = {1, 4, 8, 10};
int k = 5;
//Create an instance of Solution class
Solution solution;
//Print the answer
cout << "The " << k << "-th element of two sorted arrays is: "
<< solution.kthElement(a, b, k) << '\n';
return 0;
}
import java.util.*;
class Solution {
public int kthElement(int[] a, int[] b, int k) {
int m = a.length;
int n = b.length;
// Ensure a is smaller array for optimization
if (m > n) {
// Swap a and b
return kthElement(b, a, k);
}
// Length of the left half
int left = k;
// Apply binary search
int low = Math.max(0, k - n), high = Math.min(k, m);
while (low <= high) {
int mid1 = (low + high) >> 1;
int mid2 = left - mid1;
// Initialize l1, l2, r1, r2
int l1 = (mid1 > 0) ? a[mid1 - 1] : Integer.MIN_VALUE;
int l2 = (mid2 > 0) ? b[mid2 - 1] : Integer.MIN_VALUE;
int r1 = (mid1 < m) ? a[mid1] : Integer.MAX_VALUE;
int r2 = (mid2 < n) ? b[mid2] : Integer.MAX_VALUE;
// Check if we have found the answer
if (l1 <= r2 && l2 <= r1) {
return Math.max(l1, l2);
}
else if (l1 > r2) {
// Eliminate the right half
high = mid1 - 1;
}
else {
// Eliminate the left half
low = mid1 + 1;
}
}
// Dummy return statement
return -1;
}
public static void main(String[] args) {
int[] a = {2, 3, 6, 7, 9};
int[] b = {1, 4, 8, 10};
int k = 5;
// Create an instance of Solution class
Solution solution = new Solution();
// Print the answer
System.out.println("The " + k + "-th element of two sorted arrays is: " +solution.kthElement(a, b, k));
}
}
class Solution:
def kthElement(self, a, b, k):
m = len(a)
n = len(b)
# Ensure a is smaller array for optimization
if m > n:
# Swap a and b
return self.kthElement(b, a, k)
# Length of the left half
left = k
# Apply binary search
low = max(0, k - n)
high = min(k, m)
while low <= high:
mid1 = (low + high) >> 1
mid2 = left - mid1
# Initialize l1, l2, r1, r2
l1 = a[mid1 - 1] if mid1 > 0 else float('-inf')
l2 = b[mid2 - 1] if mid2 > 0 else float('-inf')
r1 = a[mid1] if mid1 < m else float('inf')
r2 = b[mid2] if mid2 < n else float('inf')
# Check if we have found the answer
if l1 <= r2 and l2 <= r1:
return max(l1, l2)
elif l1 > r2:
# Eliminate the right half
high = mid1 - 1
else:
# Eliminate the left half
low = mid1 + 1
# Dummy return statement
return -1
a = [2, 3, 6, 7, 9]
b = [1, 4, 8, 10]
k = 5
# Create an instance of Solution class
solution = Solution()
# Print the answer
print(f"The {k}-th element of two sorted arrays is: {solution.kthElement(a, b, k)}")
class Solution {
kthElement(a, b, k) {
let m = a.length;
let n = b.length;
// Ensure a is smaller array for optimization
if (m > n) {
// Swap a and b
return this.kthElement(b, a, k);
}
// Length of the left half
let left = k;
// Apply binary search
let low = Math.max(0, k - n);
let high = Math.min(k, m);
while (low <= high) {
let mid1 = (low + high) >> 1;
let mid2 = left - mid1;
// Initialize l1, l2, r1, r2
let l1 = (mid1 > 0) ? a[mid1 - 1] : Number.MIN_SAFE_INTEGER;
let l2 = (mid2 > 0) ? b[mid2 - 1] : Number.MIN_SAFE_INTEGER;
let r1 = (mid1 < m) ? a[mid1] : Number.MAX_SAFE_INTEGER;
let r2 = (mid2 < n) ? b[mid2] : Number.MAX_SAFE_INTEGER;
// Check if we have found the answer
if (l1 <= r2 && l2 <= r1) {
return Math.max(l1, l2);
} else if (l1 > r2) {
// Eliminate the right half
high = mid1 - 1;
} else {
// Eliminate the left half
low = mid1 + 1;
}
}
// Dummy return statement
return -1;
}
}
let a = [2, 3, 6, 7, 9];
let b = [1, 4, 8, 10];
let k = 5
//Create an instance of Solution class
let sol = new Solution();
// Print the answer
console.log(`The ${k}-th element of two sorted arrays is: ${sol.kthElement(a, b, k)}`);
Q: Why not merge the arrays to find the k-th element?
A: Merging the arrays requires O(m+n) time and space. The binary search approach avoids the full merge and works in O(log(min(m,n))), which is significantly faster and more efficient.
Q: How would you extend this to more than two arrays?
A: For k-th element across multiple sorted arrays: Use a min-heap to track the smallest elements from each array. Extract k-1 elements from the heap to find the k-th smallest. Complexity: O(k⋅log(number of arrays)).
Q: What if the arrays are unsorted?
A: If the arrays are unsorted, sort them first (O(mlogm+nlogn)), then apply the same binary search logic. Sorting adds preprocessing overhead but ensures correctness.