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 :
- Query are of type query(l, r, k)
- 1 <= k <= r-l+1
- There can be multiple queries.
Examples:
Input : arr = {3, 2, 5, 4, 7, 1, 9}, query = (2, 6, 3)
Output : 4
sorted subarray in a range 2 to 6 is {1, 2, 4, 5, 7} and 3rd element is 4Input : arr = {2, 3, 4, 1, 6, 5, 8}, query = (1, 5, 2)
Output : 2
Let, S = r - l + 1.
Naive Approach:
- Copy the subarray into some other local array. After sorting find the kth element.
Time complexity: Slog(S) - Use a max priority queue ‘p’ and iterate in the subarray. If size of ‘p’ is less than ‘k’ insert element else remove top element and insert the new element into ‘p’ after complete interaction top of ‘p’ will be the answer.
Time complexity: Slog(k)
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]); |
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