Kth Element of Merged Two Sorted Arrays (original) (raw)

Given two **sorted arrays **a[] of size **m and **b[] of size **n, find the **k-th smallest element in the combined sorted sequence of all elements from both arrays.
Assume 1-based indexing for k, and that 1 ≤ k ≤ m + n.

**Examples:

**Input: a[] = [2, 3, 6, 7, 9], b[] = [1, 4, 8, 10], k = 5
**Output: 6
**Explanation: The final sorted array is [1, 2, 3, 4, 6, 7, 8, 9, 10]. The 5th element is 6.

**Input: a[] = [1, 2, 2], b[] = [2, 3, 4], k = 4
**Output: 2
**Explanation: Merged array = [1, 2, 2, 2, 3, 4], 4th element = 2.

Table of Content

[Naive Approach 1] Using Sorting - O((m + n) × log(m + n)) Time and O(m + n) Space

The idea is to combine both arrays into a single array, then sort the combined array to get all elements in order. The kth smallest element is returned directly using its index after sorting.

C++ `

#include #include #include

using namespace std;

int kthElement(vector &a, vector &b, int k) {

// to merge both the arrays
vector<int> arr;

// add the elements of array a
for(auto i: a)
    arr.push_back(i);

// add the elements of array a
for(auto i: b)
    arr.push_back(i);

// sort the merged array
sort(arr.begin(), arr.end());

// return the kth element
return arr[k-1];

}

int main() {

vector<int> a = {2, 3, 6, 7, 9};
vector<int> b = {1, 4, 8, 10};
int k = 5;
cout << kthElement(a, b, k);

return 0;

}

Java

import java.util.Collections; import java.util.ArrayList;

class GfG {

static int kthElement(int[] a, int[] b, int k) {
    
    // to merge both the arrays
    ArrayList<Integer> arr = new ArrayList<>();
    
    // add the elements of array a
    for (int i : a)
        arr.add(i);
    
    // add the elements of array b
    for (int i : b)
        arr.add(i);
    
    // sort the merged array
    Collections.sort(arr);
    
    // return the kth element
    return arr.get(k - 1);
}

public static void main(String[] args) {
    int[] a = {2, 3, 6, 7, 9};
    int[] b = {1, 4, 8, 10};
    int k = 5;
    
    System.out.println(kthElement(a, b, k));
}

}

Python

def kthElement(a, b, k):

# to merge both the arrays
arr = []

# add the elements of array a
for i in a:
    arr.append(i)

# add the elements of array b
for i in b:
    arr.append(i)

# sort the merged array
arr.sort()

# return the kth element
return arr[k - 1]

if name == "main": a = [2, 3, 6, 7, 9] b = [1, 4, 8, 10] k = 5 print(kthElement(a, b, k))

C#

using System; using System.Collections.Generic;

class GfG {

static int kthElement(int[] a, int[] b, int k) {
    
    // to merge both the arrays
    List<int> arr = new List<int>();
    
    // add the elements of array a
    foreach (int i in a)
        arr.Add(i);
    
    // add the elements of array b
    foreach (int i in b)
        arr.Add(i);
    
    // sort the merged array
    arr.Sort();
    
    // return the kth element
    return arr[k - 1];
}

static void Main() {
    int[] a = {2, 3, 6, 7, 9};
    int[] b = {1, 4, 8, 10};
    int k = 5;
    
    Console.WriteLine(kthElement(a, b, k));
}

}

JavaScript

function kthElement(a, b, k) {

// to merge both the arrays
let arr = [];

// add the elements of array a
for (let i of a)
    arr.push(i);

// add the elements of array b
for (let i of b)
    arr.push(i);

// sort the merged array
arr.sort((x, y) => x - y);

// return the kth element
return arr[k - 1];

}

// Driver Code let a = [2, 3, 6, 7, 9]; let b = [1, 4, 8, 10]; let k = 5; console.log(kthElement(a, b, k));

`

[Naive Approach 2] Using Priority Queue - O((m + n + k) × log(m + n)) Time and O(m + n) Space

The idea is to insert all elements from both sorted arrays into a min-heap, which automatically keeps the smallest elements at the top. Then, by removing the smallest element k - 1 times, the kth smallest element will be at the top of the heap. This approach ensures the elements are processed in sorted order without full array sorting.

C++ `

#include #include #include

using namespace std;

int kthElement(vector &a, vector &b, int k){

// to store the elements of both
// the arrays in sorted order
priority_queue<int, vector<int>, greater<int>> pq;

// add the elements of array a
for(auto i: a)
    pq.push(i);

// add the elements of array a
for(auto i: b)
    pq.push(i);

// pop the elements from the heap
// till k-1 elements are popped
while(k-- > 1)
    pq.pop();

// return the kth element
return pq.top();

}

int main() {

vector<int> a = {2, 3, 6, 7, 9};
vector<int> b = {1, 4, 8, 10};
int k = 5;
cout << kthElement(a, b, k);

return 0;

}

Java

import java.util.PriorityQueue;

class GfG {

static int kthElement(int[] a, int[] b, int k){
    
    // to store the elements of both
    // the arrays in sorted order
    PriorityQueue<Integer> pq = 
                new PriorityQueue<>();
    
    // add the elements of array a
    for (int i : a)
        pq.add(i);
    
    // add the elements of array a
    for (int i : b)
        pq.add(i);
    
    // pop the elements from the heap
    // till k-1 elements are popped
    while (k-- > 1)
        pq.poll();
    
    // return the kth element
    return pq.peek();
}

public static void main(String[] args) {
    int[] a = {2, 3, 6, 7, 9};
    int[] b = {1, 4, 8, 10};
    int k = 5;
    System.out.println(kthElement(a, b, k));
}

}

Python

import heapq

def kthElement(a, b, k):

# to store the elements of both
# the arrays in sorted order
pq = []

# add the elements of array a
for i in a:
    heapq.heappush(pq, i)

# add the elements of array a
for i in b:
    heapq.heappush(pq, i)

# pop the elements from the heap
# till k-1 elements are popped
while k > 1:
    heapq.heappop(pq)
    k -= 1

# return the kth element
return pq[0]

if name == "main": a = [2, 3, 6, 7, 9] b = [1, 4, 8, 10] k = 5 print(kthElement(a, b, k))

C#

using System; using System.Collections.Generic;

class GfG { public static int kthElement(List a, List b, int k) { // to store the elements of both // the arrays in sorted order SortedDictionary<int, Queue> map = new SortedDictionary<int, Queue>();

    // add the elements of array a
    foreach (int i in a) {
        if (!map.ContainsKey(i))
            map[i] = new Queue<int>();
        map[i].Enqueue(i);
    }

    // add the elements of array b
    foreach (int i in b) {
        if (!map.ContainsKey(i))
            map[i] = new Queue<int>();
        map[i].Enqueue(i);
    }

    // pop the elements from the map
    // till k-1 elements are popped
    while (k-- > 1) {
        int minKey = firstKey(map);
        map[minKey].Dequeue();
        if (map[minKey].Count == 0)
            map.Remove(minKey);
    }

    // return the kth element
    return firstKey(map);
}

// helper to get first (smallest) key
public static int firstKey(SortedDictionary<int, Queue<int>> map){
    foreach (var kvp in map)
        return kvp.Key;
    return -1;
}

public static void Main(string[] args) {
    List<int> a = new List<int> { 2, 3, 6, 7, 9 };
    List<int> b = new List<int> { 1, 4, 8, 10 };
    int k = 5;

    Console.WriteLine(kthElement(a, b, k));
}

}

JavaScript

function kthElement(a, b, k) {

// to store the elements of both
// the arrays in sorted order
let pq = [];

// add the elements of array a
for (let i of a)
    pq.push(i);

// add the elements of array a
for (let i of b)
    pq.push(i);

// sort the merged array in ascending order
pq.sort((x, y) => x - y);

// pop the elements from the heap
// till k-1 elements are popped
while (k-- > 1)
    pq.shift();

// return the kth element
return pq[0];

}

// Driver Code let a = [2, 3, 6, 7, 9]; let b = [1, 4, 8, 10]; let k = 5; console.log(kthElement(a, b, k));

`

[Better Approach 1] Using Merge Step of Merge Sort - O(m + n) Time and O(m + n) Space

The basic idea here is to merge the given two arrays into a single sorted array and then simply return the element at the kth position. This approach is straightforward because it directly uses the merging process of two sorted arrays, similar to the merge step in the merge sort algorithm.

**Step-by-step approach:

#include #include

using namespace std;

int kthElement(vector &a, vector &b, int k){ int n = a.size(), m = b.size();

// array to store the merged sorted array
vector<int> arr(n + m);
int i = 0, j = 0, d = 0;
while (i < n && j < m) {

    // if the element of a[] is smaller, insert 
    // the element to the sorted array
    if (a[i] < b[j])
        arr[d++] = a[i++];
    
    // if the element of b[] is smaller, insert 
    // the element to the sorted array
    else
        arr[d++] = b[j++];
}

// push the remaining elements of a[]
while (i < n)
    arr[d++] = a[i++];

// push the remaining elements of b[]
while (j < m)
    arr[d++] = b[j++];

return arr[k - 1];

}

int main() { vector a = {2, 3, 6, 7, 9}; vector b = {1, 4, 8, 10}; int k = 5; cout << kthElement(a, b, k); return 0; }

Java

class GfG { static int kthElement(int[] a, int[] b, int k) { int n = a.length, m = b.length;

    // array to store the merged sorted array
    int[] arr = new int[n + m];
    int i = 0, j = 0, d = 0;

    while (i < n && j < m) {
        
        // if the element of a[] is smaller, insert 
        // the element to the sorted array
        if (a[i] < b[j]) {
            arr[d++] = a[i++];
        }
        
        // if the element of b[] is smaller, insert 
        // the element to the sorted array
        else {
            arr[d++] = b[j++];
        }
    }

    // push the remaining elements of a[]
    while (i < n) {
        arr[d++] = a[i++];
    }

    // push the remaining elements of b[]
    while (j < m) {
        arr[d++] = b[j++];
    }

    return arr[k - 1];
}

public static void main(String[] args) {
    int[] a = {2, 3, 6, 7, 9};
    int[] b = {1, 4, 8, 10};
    int k = 5;
    System.out.println(kthElement(a, b, k));
}

}

Python

def kthElement(a, b, k): n = len(a) m = len(b)

# array to store the merged sorted array
arr = [0] * (n + m)
i = 0
j = 0
d = 0
while i < n and j < m:

    # if the element of a[] is smaller, insert 
    # the element to the sorted array
    if a[i] < b[j]:
        arr[d] = a[i]
        i += 1
    
    # if the element of b[] is smaller, insert
    # the element to the sorted array
    else:
        arr[d] = b[j]
        j += 1
    d += 1

# push the remaining elements of a[]
while i < n:
    arr[d] = a[i]
    i += 1
    d += 1

# push the remaining elements of b[]
while j < m:
    arr[d] = b[j]
    j += 1
    d += 1

return arr[k - 1]

if name == "main": arr1 = [2, 3, 6, 7, 9] arr2 = [1, 4, 8, 10] k = 5 print(kthElement(arr1, arr2, k))

C#

using System; class GfG { static int kthElement(int[] a, int[] b, int k) { int n = a.Length, m = b.Length;

    // array to store the merged sorted array
    int[] arr = new int[n + m];
    int i = 0, j = 0, d = 0;

    while (i < n && j < m) {
      
        // if the element of a[] is smaller, insert 
        // the element to the sorted array
        if (a[i] < b[j])
            arr[d++] = a[i++];
        
        // if the element of b[] is smaller, insert
        // the element to the sorted array
        else
            arr[d++] = b[j++];
    }

    // push the remaining elements of a[]
    while (i < n)
        arr[d++] = a[i++];

    // push the remaining elements of b[]
    while (j < m)
        arr[d++] = b[j++];

    return arr[k - 1];
}

static void Main() {
    int[] a = { 2, 3, 6, 7, 9 };
    int[] b = { 1, 4, 8, 10 };
    int k = 5;

    Console.WriteLine(kthElement(a, b, k));
}

}

JavaScript

function kthElement(a, b, k) { const n = a.length, m = b.length;

// array to store the merged sorted array
let arr = new Array(n + m);
let i = 0, j = 0, d = 0;

while (i < n && j < m) {

    // if the element of a[] is smaller, insert 
    // the element to the sorted array
    if (a[i] < b[j])
        arr[d++] = a[i++];
    
    // if the element of b[] is smaller, insert 
    // the element to the sorted array
    else
        arr[d++] = b[j++];
}

// push the remaining elements of a[]
while (i < n)
    arr[d++] = a[i++];

// push the remaining elements of b[]
while (j < m)
    arr[d++] = b[j++];

return arr[k - 1];

}

// Driver code let a = [2, 3, 6, 7, 9]; let b = [1, 4, 8, 10]; let k = 5; console.log(kthElement(a, b, k));

`

[Better Approach 2] Using Optimized Merge of Merge Sort - O(k) Time and O(1) Space

The idea is to simulate the process of merging two sorted arrays, similar to the merge step in merge sort, but only until the k-th element is reached. We use two pointers, one for each array, and at each step, we choose the smaller of the two current elements to move forward. This way, we don't need to fully merge both arrays. We only track the last selected element, which will be the k-th smallest.

C++ `

#include #include using namespace std;

int kthElement(vector &a, vector &b, int k){ int n = a.size(), m = b.size();

// last element added to the merged 
// sorted array
int last = 0;
int i = 0, j = 0;

for (int d = 0; d < k; ++d) {
    if (i < n) {
      
        // if a[i] > b[j] then increment j
        if (j < m && a[i] > b[j]) {
            last = b[j];
            j++;
        } 
        // otherwise increment i
        else {
            last = a[i];
            i++;
        }
    }
    
    // if reached end of first array then 
    // increment j
    else if (j < m) {
        last = b[j];
        j++;
    }
}

// return the last (kth) element
return last;

}

int main() { vector a = {2, 3, 6, 7, 9}; vector b = {1, 4, 8, 10}; int k = 5;

cout << kthElement(a, b, k) << endl;
return 0;

}

Java

class GfG { static int kthElement(int[] a, int[] b, int k){ int n = a.length, m = b.length;

    // last element added to the merged 
    // sorted array
    int last = 0;
      int i = 0, j = 0;

    for (int d = 0; d < k; ++d) {
        if (i < n) {
          
              // if a[i] > b[j] then increment j
            if (j < m && a[i] > b[j]) {
                last = b[j];
                j++;
            } 
              
              // otherwise increment i
              else {
                last = a[i];
                i++;
            }
        } 
          
          // if reached end of first array then 
          // increment j
          else if (j < m) {
            last = b[j];
            j++;
        }
    }

      // return the last (kth) element
    return last;
}

public static void main(String[] args) {
    int[] a = {2, 3, 6, 7, 9};
    int[] b = {1, 4, 8, 10};
    int k = 5;
    System.out.println(kthElement(a, b, k));
}

}

Python

def kthElement(a, b, k): n, m = len(a), len(b)

# last element added to the merged 
# sorted array
last = 0
i, j = 0, 0

for _ in range(k):
    if i < n:
        # If a[i] > b[j] then increment j
        if j < m and a[i] > b[j]:
            last = b[j]
            j += 1
        # Otherwise increment i
        else:
            last = a[i]
            i += 1
    
    # if reached end of first array then 
    # increment j
    elif j < m:
        last = b[j]
        j += 1

# Return the last (kth) element
return last

if name == "main": a = [2, 3, 6, 7, 9] b = [1, 4, 8, 10] k = 5 print(kthElement(a, b, k))

C#

using System; class GfG { static int KthElement(int[] a, int[] b, int k){ int n = a.Length, m = b.Length;

    // last element added to the merged
    // sorted array
    int last = 0;
    int i = 0, j = 0;

    for (int d = 0; d < k; ++d) {
        if (i < n) {
            
            // if a[i] > b[j] then increment j
            if (j < m && a[i] > b[j]) {
                last = b[j];
                j++;
            }
            
            // otherwise increment i
            else {
                last = a[i];
                i++;
            }
        }
        // if reached end of first array then 
        // increment j
        else if (j < m) {
            last = b[j];
            j++;
        }
    }

    // return the last (kth) element
    return last;
}

public static void Main(string[] args) {
    int[] a = { 2, 3, 6, 7, 9 };
    int[] b = { 1, 4, 8, 10 };
    int k = 5;

    Console.WriteLine(KthElement(a, b, k));
}

}

JavaScript

function kthElement(a, b, k) { const n = a.length, m = b.length; // last element added to the merged // sorted array let last = 0; let i = 0, j = 0;

for (let d = 0; d < k; ++d) {
    if (i < n) {
        // if a[i] > b[j] then increment j
        if (j < m && a[i] > b[j]) {
            last = b[j];
            j++;
        } 
        
        // otherwise increment i
        else {
            last = a[i];
            i++;
        }
    } 
    // if reached end of first array then 
    // increment j
    else if (j < m) {
        last = b[j];
        j++;
    }
}

// return the last (kth) element
return last;

}

// Driver code const a = [2, 3, 6, 7, 9]; const b = [1, 4, 8, 10]; const k = 5; console.log(kthElement(a, b, k));

`

[Expected Approach] Using Binary Search - O(log min(n, m)) Time and O(1) Space

The approach is similar to the Binary Search approach of **Median of two sorted arrays of different sizes.

Consider the first array is smaller. If first array is greater, then swap the arrays to make sure that the first array is smaller.

#include #include #include using namespace std;

int kthElement(vector &a, vector &b, int k) { int n = a.size(), m = b.size();

// if a[] has more elements, then call 
// kthElement with reversed parameters
if (n > m)
    return kthElement(b, a, k);

// binary Search on the number of elements we can
// include in the first set from a[]
int lo = max(0, k - m), hi = min(k, n);

while (lo <= hi) {
    int mid1 = (lo + hi) / 2;
    int mid2 = k - mid1;

    // find elements to the left and right of 
    // partition in a[]
    int l1 = (mid1 == 0 ? INT_MIN : a[mid1 - 1]);
    int r1 = (mid1 == n ? INT_MAX : a[mid1]);

    // find elements to the left and right of 
    // partition in b[]
    int l2 = (mid2 == 0 ? INT_MIN : b[mid2 - 1]);
    int r2 = (mid2 == m ? INT_MAX : b[mid2]);

    // if it is a valid partition
    if (l1 <= r2 && l2 <= r1) {
          
          // find and return the maximum of l1 and l2
        return max(l1, l2);
    }

    // check if we need to take lesser elements from a[]
    if (l1 > r2)
        hi = mid1 - 1;

    // check if we need to take more elements from a[]
    else
        lo = mid1 + 1;
}

return 0;

}

int main() { vector a = {2, 3, 6, 7, 9}; vector b = {1, 4, 8, 10}; int k = 5; cout << kthElement(a, b, k); return 0; }

Java

class GfG { static int kthElement(int[] a, int[] b, int k) { int n = a.length, m = b.length;

    // if a[] has more elements, then call 
    // kthElement with reversed parameters
    if (n > m)
        return kthElement(b, a, k);

    // binary Search on the number of elements we 
    // can include in the first set from a[]
    int lo = Math.max(0, k - m), hi = Math.min(k, n);

    while (lo <= hi) {
        int mid1 = (lo + hi) / 2;
        int mid2 = k - mid1;

        // find elements to the left and right of 
        // partition in a[]
        int l1 = (mid1 == 0 ? Integer.MIN_VALUE : 
                                      a[mid1 - 1]);
        int r1 = (mid1 == n ? Integer.MAX_VALUE : 
                                          a[mid1]);

        // find elements to the left and right of 
        // partition in a[]
        int l2 = (mid2 == 0 ? Integer.MIN_VALUE : 
                                      b[mid2 - 1]);
        int r2 = (mid2 == m ? Integer.MAX_VALUE :
                                          b[mid2]);

        // if it is a valid partition
        if (l1 <= r2 && l2 <= r1) {
            // find and return the maximum of l1 and l2
            return Math.max(l1, l2);
        }

        // check if we need to take lesser elements
        // from a[]
        if (l1 > r2)
            hi = mid1 - 1;

        // check if we need to take more elements 
        // from a[]
        else
            lo = mid1 + 1;
    }

    return 0;
}

public static void main(String[] args) {
    int[] a = {2, 3, 6, 7, 9};
    int[] b = {1, 4, 8, 10};
    int k = 5;
    System.out.println(kthElement(a, b, k));
}

}

Python

def kthElement(a, b, k): n = len(a) m = len(b)

# if a[] has more elements, then call kthElement
# with reversed parameters
if n > m:
    return kthElement(b, a, k)

# binary Search on the number of elements we can
# include in the first set from a[]
lo = max(0, k - m)
hi = min(k, n)

while lo <= hi:
    mid1 = (lo + hi) // 2
    mid2 = k - mid1

    # find elements to the left and right of
    # partition in a[]
    l1 = (mid1 == 0 and float('-inf') or a[mid1 - 1])
    r1 = (mid1 == n and float('inf') or a[mid1])

    # find elements to the left and right of
    # partition in b[]
    l2 = (mid2 == 0 and float('-inf') or b[mid2 - 1])
    r2 = (mid2 == m and float('inf') or b[mid2])

    # if it is a valid partition
    if l1 <= r2 and l2 <= r1:
      
        # find and return the maximum of l1 and l2
        return max(l1, l2)

    # check if we need to take lesser elements 
    # from a[]
    if l1 > r2:
        hi = mid1 - 1

    # check if we need to take more elements
    # from a[]
    else:
        lo = mid1 + 1

return 0

if name == "main": a = [2, 3, 6, 7, 9] b = [1, 4, 8, 10] k = 5 print(kthElement(a, b, k))

C#

using System; class GfG { static int kthElement(int[] a, int[] b, int k) { int n = a.Length, m = b.Length;

    // if a[] has more elements, then call kthElement
    // with reversed parameters
    if (n > m)
        return kthElement(b, a, k);

    // binary Search on the number of elements we can
    // include in the first set from a[]
    int lo = Math.Max(0, k - m), hi = Math.Min(k, n);

    while (lo <= hi) {
        int mid1 = (lo + hi) / 2;
        int mid2 = k - mid1;

        // find elements to the left and right of 
        // partition in a[]
        int l1 = (mid1 == 0 ? Int32.MinValue : a[mid1 - 1]);
        int r1 = (mid1 == n ? Int32.MaxValue : a[mid1]);

        // find elements to the left and right of 
        // partition in b[]
        int l2 = (mid2 == 0 ? Int32.MinValue : b[mid2 - 1]);
        int r2 = (mid2 == m ? Int32.MaxValue : b[mid2]);

        // if it is a valid partition
        if (l1 <= r2 && l2 <= r1) {
          
            // find and return the maximum of l1 and l2
            return Math.Max(l1, l2);
        }

        // check if we need to take lesser
        // elements from a[]
        if (l1 > r2)
            hi = mid1 - 1;

        // check if we need to take more
        // elements from a[]
        else
            lo = mid1 + 1;
    }

    return 0;
}

static void Main() {
    int[] a = { 2, 3, 6, 7, 9 };
    int[] b = { 1, 4, 8, 10 };
    int k = 5;
    Console.WriteLine(kthElement(a, b, k));
}

}

JavaScript

function kthElement(a, b, k) { let n = a.length, m = b.length;

// if a[] has more elements, then call kthElement
// with reversed parameters
if (n > m) {
    return kthElement(b, a, k);
}

// binary Search on the number of elements we can
// include in the first set from a[]
let lo = Math.max(0, k - m), hi = Math.min(k, n);

while (lo <= hi) {
    let mid1 = Math.floor((lo + hi) / 2);
    let mid2 = k - mid1;

    // find elements to the left and right of partition in a[]
    let l1 = (mid1 === 0 ? -Infinity : a[mid1 - 1]);
    let r1 = (mid1 === n ? Infinity : a[mid1]);

    // find elements to the left and right of partition in b[]
    let l2 = (mid2 === 0 ? -Infinity : b[mid2 - 1]);
    let r2 = (mid2 === m ? Infinity : b[mid2]);

    // if it is a valid partition
    if (l1 <= r2 && l2 <= r1) {

        // find and return the maximum of l1 and l2
        return Math.max(l1, l2);
    }

    // check if we need to take lesser 
    // elements from a[]
    if (l1 > r2) {
        hi = mid1 - 1;
    }

    // check if we need to take more 
    // elements from a[]
    else {
        lo = mid1 + 1;
    }
}

return 0;

}

// Driver Code const a = [2, 3, 6, 7, 9]; const b = [1, 4, 8, 10]; const k = 5; console.log(kthElement(a, b, k));

`