Given that integers are being read from a data stream. Find the median of all the elements read so far starting from the first integer until the last integer. This is also called Median of Running Integers. The given link already contains solution of this problem using Priority Queue. However, the following solution uses the same concept but the implementation is by using sets. In this solution, we will print the smaller median in case of even length instead of taking their average.
Examples:
Input: arr[] = {-10, 14, 11, -5, 7}
Output: -10 -10 11 -5 7Input: arr[] = {2, -5, 14}
Output: 2 -5 2
Approach:
- Create two multisets g in ascending order that will store the upper half and s in descending order to store the lower half of the array arr[].
- Insert the first element in s. And initialize the median with this value.
- For every other element of the array x. Check the sizes of both the sets:
- When size(s) > size(g): If x > median then insert the first element of s into g and remove that element from s, insert x into s. Else insert x into g.Median = top/begin of set with larger size.
- When size(s) < size(g): If x < median then insert the first element of g into s and remove that element from g, insert x into g. Else insert x into s. Median = top/begin of set with larger size.
- When size(s) = size(g): If x > median. Insert x into s, Median = begin of g. Else insert x into g.
Below is the implementation of the above approach:
// C++ program to find running median for // a stream of integers using Set #include <bits/stdc++.h> using namespace std;
// Function to print the running median // for the array arr[] void printRunningMedian( int arr[], int n)
{ // Multiset is used to handle duplicates
// Multiset g for storing upper half
// (ascending order)
// The first element will be the smallest)
multiset< int > g;
// Multiset s for storing lower half
// (descending order). The first element
// will be the largest
multiset< int , greater< int > > s;
s.insert(arr[0]);
// Initialise median with the first element
int med = arr[0];
printf ( "%d " , med);
for ( int i = 1; i < n; i++) {
// Only add elements to upper half if
// its size less than the size of the
// lower half (maintain only difference
// of 1)
if (s.size() > g.size()) {
if (arr[i] < med) {
int temp = *s.begin();
s.erase(s.begin());
g.insert(temp);
s.insert(arr[i]);
}
else
g.insert(arr[i]);
//median = top/begin of set with larger size = g.begin or s.begin
med = *s.begin() > *g.begin() ?
*g.begin() : *s.begin();
}
// Only add elements to lower half if
// it's size less than the size of the
// upper half (maintain only difference
// of 1)
else if (s.size() < g.size()) {
if (arr[i] > med) {
int temp = *g.begin();
g.erase(g.begin());
s.insert(temp);
g.insert(arr[i]);
}
else
s.insert(arr[i]);
//median = top/begin of set with larger size = g.begin or s.begin
med = *s.begin() > *g.begin() ?
*g.begin() : *s.begin();
}
// If sizes are same
else {
if (arr[i] > med) {
g.insert(arr[i]);
//median = first element/begin of g
med = *g.begin();
}
else {
s.insert(arr[i]);
//median = first element/begin of s
med = *s.begin();
}
}
printf ( "%d " , med);
}
printf ( "\n" );
} // Driver code int main()
{ int arr[] = { -10, 14, 11, -5, 7 };
int n = sizeof (arr) / sizeof (arr[0]);
printRunningMedian(arr, n);
return 0;
} |
def printRunningMedian(arr):
# Set g for storing upper half (ascending order)
# The first element will be the smallest
g = set ()
# Set s for storing lower half (descending order)
# The first element will be the largest
s = set ()
s.add(arr[ 0 ])
# Initialize median with the first element
med = arr[ 0 ]
print (med, end = " " )
for i in range ( 1 , len (arr)):
# Only add elements to upper half if
# its size less than the size of
# the lower half (maintain only difference of 1)
if len (s) > len (g):
if arr[i] < med:
temp = max (s)
s.remove(temp)
g.add(temp)
s.add(arr[i])
else :
g.add(arr[i])
# median = top/begin of set with larger size = g.begin or s.begin
med = min (g) if max (s) > min (g) else max (s)
# Only add elements to lower half if its size
# less than the size of the upper half (maintain only difference of 1)
elif len (s) < len (g):
if arr[i] > med:
temp = min (g)
g.remove(temp)
s.add(temp)
g.add(arr[i])
else :
s.add(arr[i])
# median = top/begin of set with larger size = g.begin or s.begin
med = min (g) if max (s) > min (g) else max (s)
# If sizes are same
else :
if arr[i] > med:
g.add(arr[i])
# median = first element/begin of g
med = min (g)
else :
s.add(arr[i])
# median = first element/begin of s
med = max (s)
print (med, end = " " )
# Driver code to test above function arr = [ - 10 , 14 , 11 , - 5 , 7 ]
printRunningMedian(arr) |
import java.util.TreeSet;
public class Solution {
// Function to print the running median
// for the array arr[]
public static void printRunningMedian( int [] arr, int n) {
// Multiset is used to handle duplicates
// Multiset g for storing upper half
// (ascending order)
// The first element will be the smallest)
TreeSet<Integer> g = new TreeSet<Integer>();
// Multiset s for storing lower half
// (descending order). The first element
// will be the largest
TreeSet<Integer> s = new TreeSet<Integer>((a, b) -> (b - a));
s.add(arr[ 0 ]);
// Initialise median with the first element
int med = arr[ 0 ];
System.out.print(med + " " );
for ( int i = 1 ; i < n; i++) {
// Only add elements to upper half if
// its size less than the size of the
// lower half (maintain only difference
// of 1)
if (s.size() > g.size()) {
if (arr[i] < med) {
int temp = s.first();
s.remove(s.first());
g.add(temp);
s.add(arr[i]);
} else {
g.add(arr[i]);
}
//median = first element/begin of set with larger
// size = g.first or s.first
med = s.first() > g.first() ? g.first() : s.first();
}
// Only add elements to lower half if
// it's size less than the size of the
// upper half (maintain only difference
// of 1)
else if (s.size() < g.size()) {
if (arr[i] > med) {
int temp = g.first();
g.remove(g.first());
s.add(temp);
g.add(arr[i]);
} else {
s.add(arr[i]);
}
//median = first element/begin of set with
//larger size = g.first or s.first
med = s.first() > g.first() ? g.first() : s.first();
}
// If sizes are same
else {
if (arr[i] > med) {
g.add(arr[i]);
//median = first element/begin of g
med = g.first();
} else {
s.add(arr[i]);
//median = first element/begin of s
med = s.first();
}
}
System.out.print(med + " " );
}
System.out.println();
}
// Driver code
public static void main(String[] args) {
int [] arr = { - 10 , 14 , 11 , - 5 , 7 };
int n = arr.length;
printRunningMedian(arr, n);
}
} |
using System;
using System.Collections.Generic;
class GFG
{ static void PrintRunningMedian( int [] arr, int n)
{
// Multiset is used to handle duplicates
// Multiset g for storing upper half
// (ascending order)
// The first element will be the smallest)
SortedSet< int > g = new SortedSet< int >();
// Multiset s for storing lower half
// (descending order). The first element
// will be the largest
SortedSet< int > s = new SortedSet< int >(Comparer< int >.Create((a, b) => b.CompareTo(a)));
s.Add(arr[0]);
// Initialise median with the first element
int med = arr[0];
Console.Write(med + " " );
for ( int i = 1; i < n; i++)
{
// Only add elements to upper half if
// its size less than the size of the
// lower half (maintain only difference
// of 1)
if (s.Count > g.Count)
{
if (arr[i] < med)
{
int temp = s.Min;
s.Remove(temp);
g.Add(temp);
s.Add(arr[i]);
}
else
{
g.Add(arr[i]);
}
//median = top/begin of set with larger size = g.Min or s.Min
med = s.Min > g.Min ? g.Min : s.Min;
}
// Only add elements to lower half if
// it's size less than the size of the
// upper half (maintain only difference
// of 1)
else if (s.Count < g.Count)
{
if (arr[i] > med)
{
int temp = g.Min;
g.Remove(temp);
s.Add(temp);
g.Add(arr[i]);
}
else
{
s.Add(arr[i]);
}
//median = top/begin of set with larger size = g.Min or s.Min
med = s.Min > g.Min ? g.Min : s.Min;
}
// If sizes are same
else
{
if (arr[i] > med)
{
g.Add(arr[i]);
//median = first element/begin of g
med = g.Min;
}
else
{
s.Add(arr[i]);
//median = first element/begin of s
med = s.Min;
}
}
Console.Write(med + " " );
}
Console.WriteLine();
}
static void Main( string [] args)
{
int [] arr = { -10, 14, 11, -5, 7 };
int n = arr.Length;
PrintRunningMedian(arr, n);
}
} // This code is contributed By Shivam Tiwari |
function printRunningMedian(arr)
{ // Set g for storing upper half (ascending order)
// The first element will be the smallest
let g = new Set();
// Set s for storing lower half (descending order)
// The first element will be the largest
let s = new Set();
s.add(arr[0]);
// Initialize median with the first element
let med = arr[0];
process.stdout.write(med + " " );
for (let i = 1; i < arr.length; i++)
{
// Only add elements to upper half if
// its size less than the size of
// the lower half (maintain only difference of 1)
if (s.size > g.size) {
if (arr[i] < med) {
let temp = Math.max(...s);
s. delete (temp);
g.add(temp);
s.add(arr[i]);
} else {
g.add(arr[i]);
}
// median = top/begin of set with larger size = g.begin or s.begin
med = Math.max(...s) > Math.min(...g) ? Math.min(...g) : Math.max(...s);
}
// Only add elements to lower half if its size
// less than the size of the upper half (maintain only difference of 1)
else if (s.size < g.size) {
if (arr[i] > med) {
let temp = Math.min(...g);
g. delete (temp);
s.add(temp);
g.add(arr[i]);
} else {
s.add(arr[i]);
}
// median = top/begin of set with larger size = g.begin or s.begin
med = Math.max(...s) > Math.min(...g) ? Math.min(...g) : Math.max(...s);
}
// If sizes are same
else {
if (arr[i] > med) {
g.add(arr[i]);
// median = first element/begin of g
med = Math.min(...g);
} else {
s.add(arr[i]);
// median = first element/begin of s
med = Math.max(...s);
}
}
process.stdout.write(med + " " );
}
} // Driver code let arr = [-10, 14, 11, -5, 7]; printRunningMedian(arr); |
-10 -10 11 -5 7