Open In App

Kth smallest element in a subarray

Given an array arr of size N. The task is to find the kth smallest element in the subarray(l to r, both inclusive). 

Note : 

Examples:  

Input : arr = {3, 2, 5, 4, 7, 1, 9}, query = (2, 6, 3) 
Output :
sorted subarray in a range 2 to 6 is {1, 2, 4, 5, 7} and 3rd element is 4

Input : arr = {2, 3, 4, 1, 6, 5, 8}, query = (1, 5, 2) 
Output : 2

Let, S = r - l + 1.

Naive Approach:  

Efficient Approach: The idea is to use Segment trees, to be more precise use merge sort segment tree. Here, Instead of storing sorted elements we store indexes of sorted elements.

Let B is the array after sorting arr and seg is our segment tree. Node ci of seg stores the sorted order of indices of arr which are in range [st, end].

If arr = {3, 1, 5, 2, 4, 7, 8, 6},
then B is {1, 2, 3, 4, 5, 6, 7, 8}

Segment tree will look like : 

Let’s suppose seg[ci]->left holds p elements. If p is less than or equals to k, we can find kth smallest in left child and if p is less than k then move to right child and find (k-p) smallest element.

One can find the number of elements in the sorted array(A) lying in between elements X and Y by: 

upper_bound(A.begin(), A.end(), Y)-lower_bound(A.begin(), A.end(), X)

Below is the implementation of the above approach:  




// C++ program to find the kth smallest element in a range
#include <bits/stdc++.h>
using namespace std;
#define N (int)1e5
 
// Declaring a global segment tree
vector<int> seg[N];
 
// Function to build the merge sort
// segment tree of indices
void build(int ci, int st, int end,
           pair<int, int>* B)
{
    if (st == end) {
        // Using second property of B
        seg[ci].push_back(B[st].second);
        return;
    }
 
    int mid = (st + end) / 2;
    build(2 * ci + 1, st, mid, B);
    build(2 * ci + 2, mid + 1, end, B);
 
    // Inbuilt merge function
    // this takes two sorted arrays and merge
    // them into a sorted array
    merge(seg[2 * ci + 1].begin(), seg[2 * ci + 1].end(),
          seg[2 * ci + 2].begin(), seg[2 * ci + 2].end(),
          back_inserter(seg[ci]));
}
 
// Function to return the index of
// kth smallest element in range [l, r]
int query(int ci, int st, int end,
          int l, int r, int k)
{
    // Base case
    if (st == end)
        return seg[ci][0];
 
    // Finding value of 'p' as described in article
    // seg[2*ci+1] is left node of seg[ci]
    int p = upper_bound(seg[2 * ci + 1].begin(),
                        seg[2 * ci + 1].end(), r)
            - lower_bound(seg[2 * ci + 1].begin(),
                          seg[2 * ci + 1].end(), l);
 
    int mid = (st + end) / 2;
    if (p >= k)
        return query(2 * ci + 1, st, mid, l, r, k);
    else
        return query(2 * ci + 2, mid + 1, end, l, r, k - p);
}
 
// Driver code
int main()
{
    int arr[] = { 3, 1, 5, 2, 4, 7, 8, 6 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    pair<int, int> B[n];
 
    for (int i = 0; i < n; i++) {
        B[i] = { arr[i], i };
    }
 
    // After sorting, B's second property is
    // something upon which we will build our Tree
    sort(B, B + n);
 
    // Build the tree
    build(0, 0, n - 1, B);
 
    cout << "3rd smallest element in range 3 to 7 is: "
         << arr[query(0, 0, n - 1, 2, 6, 3)] << "\n";
}




// Java program to find the kth smallest element in a range
import java.util.Arrays;
 
public class Main {
  static final int N = 100000;
 
  // Declaring a global segment tree
  static int[][] seg = new int[N][0];
 
  // Function to build the merge sort
  // segment tree of indices
  static void build(int ci, int st, int end, int[][] B)
  {
    if (st == end) {
      // Using second property of B
      seg[ci] = new int[] { B[st][1] };
      return;
    }
 
    int mid = (st + end) / 2;
    build(2 * ci + 1, st, mid, B);
    build(2 * ci + 2, mid + 1, end, B);
 
    // Inbuilt merge function
    // this takes two sorted arrays and merge
    // them into a sorted array
    seg[ci] = merge(seg[2 * ci + 1], seg[2 * ci + 2]);
  }
 
  // Merge two sorted arrays into a sorted array
  static int[] merge(int[] a, int[] b)
  {
    int i = 0, j = 0, k = 0;
    int[] res = new int[a.length + b.length];
 
    while (i < a.length && j < b.length) {
      if (a[i] < b[j]) {
        res[k++] = a[i++];
      }
      else {
        res[k++] = b[j++];
      }
    }
    while (i < a.length) {
      res[k++] = a[i++];
    }
    while (j < b.length) {
      res[k++] = b[j++];
    }
    return res;
  }
 
  // Function to return the index of
  // kth smallest element in range [l, r]
  static int query(int ci, int st, int end, int l, int r,
                   int k)
  {
    if (st == end)
      return seg[ci][0];
 
    // Finding value of 'p' as described in article
    // seg[2*ci+1] is left node of seg[ci]
    int p = 0;
    for (int i = 0; i < seg[2 * ci + 1].length; i++) {
      if (seg[2 * ci + 1][i] >= l
          && seg[2 * ci + 1][i] <= r) {
        p++;
      }
    }
 
    int mid = (st + end) / 2;
    if (p >= k)
      return query(2 * ci + 1, st, mid, l, r, k);
    else
      return query(2 * ci + 2, mid + 1, end, l, r,
                   k - p);
  }
 
  // Driver code
  public static void main(String[] args)
  {
    int[] arr = { 3, 1, 5, 2, 4, 7, 8, 6 };
    int n = arr.length;
 
    int[][] B = new int[n][];
    for (int i = 0; i < n; i++) {
      B[i] = new int[] { arr[i], i };
    }
    // After sorting, B's second property is
    // something upon which we will build our Tree
    Arrays.sort(B,
                (a, b) -> Integer.compare(a[0], b[0]));
 
    // Build the tree
    build(0, 0, n - 1, B);
 
    System.out.println(
      "3rd smallest element in range 3 to 7 is: "
      + arr[query(0, 0, n - 1, 2, 6, 3)]);
  }
}
 
// This code is contributed by rutikbhosale




#Python code for the above approach
 
# Declaring a global segment tree
N = int(1e5)
seg = [[] for _ in range(N)]
 
# Function to build the merge sort segment tree of indices
def build(ci, st, end, B):
    if st == end:
        # Using second property of B
        seg[ci].append(B[st][1])
        return
 
    mid = (st + end) // 2
    build(2 * ci + 1, st, mid, B)
    build(2 * ci + 2, mid + 1, end, B)
 
    # Inbuilt merge function
    # This takes two sorted arrays and merges
    # them into a sorted array
    seg[ci].extend(sorted(seg[2 * ci + 1] + seg[2 * ci + 2]))
# Function to return the index of
# kth smallest element in range [l, r]
def query(ci, st, end, l, r, k):
    # Base case
    if st == end:
        return seg[ci][0]
 
    # Finding value of 'p' as described in the article
    # seg[2*ci+1] is the left node of seg[ci]
    p = len([x for x in seg[2 * ci + 1] if l <= x <= r])
 
    mid = (st + end) // 2
    if p >= k:
        return query(2 * ci + 1, st, mid, l, r, k)
    else:
        return query(2 * ci + 2, mid + 1, end, l, r, k - p)
 
# Driver code
if __name__ == "__main__":
    arr = [3, 1, 5, 2, 4, 7, 8, 6]
    n = len(arr)
 
    B = [(arr[i], i) for i in range(n)]
 
    # After sorting, B's second property is
    # something upon which we will build our Tree
    B.sort()
 
    # Build the tree
    build(0, 0, n - 1, B)
 
    print("3rd smallest element in range 3 to 7 is:",
          arr[query(0, 0, n - 1, 2, 6, 3)])
#This code is contributed by Potta Lokesh




// C# program to find the kth smallest element in a range
using System;
 
public class Program
{
    static readonly int N = 100000;
 
    // Declaring a global segment tree
    static int[][] seg = new int[N][];
 
    // Function to build the merge sort
    // segment tree of indices
    static void Build(int ci, int st, int end, int[][] B)
    {
        if (st == end)
        {
            // Using second property of B
            seg[ci] = new int[] { B[st][1] };
            return;
        }
 
        int mid = (st + end) / 2;
        Build(2 * ci + 1, st, mid, B);
        Build(2 * ci + 2, mid + 1, end, B);
 
        // Inbuilt merge function
        // this takes two sorted arrays and merge
        // them into a sorted array
        seg[ci] = Merge(seg[2 * ci + 1], seg[2 * ci + 2]);
    }
 
    // Merge two sorted arrays into a sorted array
    static int[] Merge(int[] a, int[] b)
    {
        int i = 0, j = 0, k = 0;
        int[] res = new int[a.Length + b.Length];
 
        while (i < a.Length && j < b.Length)
        {
            if (a[i] < b[j])
            {
                res[k++] = a[i++];
            }
            else
            {
                res[k++] = b[j++];
            }
        }
        while (i < a.Length)
        {
            res[k++] = a[i++];
        }
        while (j < b.Length)
        {
            res[k++] = b[j++];
        }
        return res;
    }
 
    // Function to return the index of
    // kth smallest element in range [l, r]
    static int Query(int ci, int st, int end, int l, int r,
                   int k)
    {
        if (st == end)
            return seg[ci][0];
 
        // Finding value of 'p' as described in article
        // seg[2*ci+1] is left node of seg[ci]
        int p = 0;
        for (int i = 0; i < seg[2 * ci + 1].Length; i++)
        {
            if (seg[2 * ci + 1][i] >= l
                && seg[2 * ci + 1][i] <= r)
            {
                p++;
            }
        }
 
        int mid = (st + end) / 2;
        if (p >= k)
            return Query(2 * ci + 1, st, mid, l, r, k);
        else
            return Query(2 * ci + 2, mid + 1, end, l, r,
                   k - p);
    }
 
  static void Main(string[] args)
    {
        int[] arr = { 3, 1, 5, 2, 4, 7, 8, 6 };
        int n = arr.Length;
 
        int[][] B = new int[n][];
        for (int i = 0; i < n; i++)
        {
            B[i] = new int[] { arr[i], i };
        }
 
        Array.Sort(B, (a, b) => a[0].CompareTo(b[0]));
 
        Build(0, 0, n - 1, B);
 
        Console.WriteLine("3rd smallest element in range 3 to 7 is: " + arr[Query(0, 0, n - 1, 2, 6, 3)]);
    }
}




// JavaScript program to find the kth smallest element in a range
const N = 1e5;
 
// Declaring a global segment tree
const seg = new Array(N).fill([]);
 
// Function to build the merge sort
// segment tree of indices
function build(ci, st, end, B) {
    if (st === end) {
        // Using second property of B
        seg[ci].push(B[st][1]);
        return;
    }
 
    let mid = Math.floor((st + end) / 2);
    build(2 * ci + 1, st, mid, B);
    build(2 * ci + 2, mid + 1, end, B);
 
    // Inbuilt merge function
    // this takes two sorted arrays and merge
    // them into a sorted array
    seg[ci] = [...seg[2 * ci + 1], ...seg[2 * ci + 2]].sort((a, b) => a - b);
}
 
// Function to return the index of
// kth smallest element in range [l, r]
function query(ci, st, end, l, r, k) {
    // Base case
    if (st === end)
        return seg[ci][0];
 
    // Finding value of 'p' as described in article
    // seg[2*ci+1] is left node of seg[ci]
    let p = seg[2 * ci + 1].filter(x => x >= l && x <= r).length;
 
    let mid = Math.floor((st + end) / 2);
    if (p >= k)
        return query(2 * ci + 1, st, mid, l, r, k);
    else
        return query(2 * ci + 2, mid + 1, end, l, r, k - p);
}
 
// Driver code
let arr = [3, 1, 5, 2, 4, 7, 8, 6];
let n = arr.length;
 
let B = [];
 
for (let i = 0; i < n; i++) {
    B[i] = [arr[i], i];
}
 
// After sorting, B's second property is
// something upon which we will build our Tree
B.sort((a, b) => a[0] - b[0]);
 
// Build the tree
build(0, 0, n - 1, B);
document.write("3rd smallest element in range 3 to 7 is: " +
arr[query(0, 0, n - 1, 2, 6, 3)+1]);

Output: 
3rd smallest element in range 3 to 7 is: 5

 

Time complexity: 
To build segment tree: O(n*log(n)) 
For each query : O(log(n)*log(n))

Auxiliary Space: O(n+N) where N=1e5
 


Article Tags :