Skip to content
Related Articles

Related Articles

Improve Article

Queries to calculate average of an array after removing K smallest and largest elements with updates

  • Last Updated : 18 Jun, 2021

Given two positive integers N and K, initialize an empty array arr[] and Q number of queries of the following two types:

The task is to process the given queries and print the results accordingly.

Examples:

Input: N = 3, K = 1, Q = 5, Queries[] = { addInteger(4), addInteger(2), calculateSpecialAverage(), addInteger(10), calculateSpecialAverage() }
Output: -1, 4
Explanation:
Below are the queries performed:
Query 1 is to insert element 4 in the array, arr[] becomes {4}.
Query 2 is to insert the element 2 in the array, arr[] becomes {4, 2}.
Query 3 is to find the average. Since the size of the array is less than N(= 3), print -1.
Query 4 is to insert the element 10 in the array, arr[] becomes {4, 2, 10}.
Query 5 is to find the average. Since the size of the array =3, remove K(= 1) the smallest element i.e., 2 and then remove the largest element i.e., 10. Now the average will be 4/1 = 4.

Input: N = 3, K = 1, Q = 5, Queries[] = { addInteger(4), addInteger(21), calculateSpecialAverage() }
Output: -1



Approach: The given problem can be solved by using the multiset. Follow the steps below to solve the problem:

  • Initialize three multisets left, right and mid to store K smallest, K largest, and the remaining (N – 2*K) integers.
  • Declare a vector v of size N to store the last N integers.
  • Declare an integer variable pos to keep track of the current index and an integer sum to store the sum of values in the mid multiset, which is the desired sum for calculating the average of (N – 2*K) integers.
  • Define a function add to insert an integer in left, mid, or right multiset based on its value. To insert integer in the correct multiset follow the following steps:
    • Initially, insert the integer in the left multiset.
    • If the size of the left multiset exceeds k, delete the largest integer from the left multiset and insert it in the mid multiset.
    • If the size of mid multiset exceeds (n – 2*k), delete the largest integer from mid multiset and insert it in the right multiset.
    • While removing and adding integers in mid multiset maintain the correct value of sum i.e. if an integer is removed from mid multiset subtract its value from the sum and similarly if an integer is added in the mid multiset, add its value to sum, to keep the value of sum updated.
  • Declare a function remove to erase the integers from left, right, or mid multiset.
    • If the value of the integer num is less than or equal to the largest integer in the left multiset, then find and erase the integer from the left multiset, otherwise search for it in mid or right multiset, based on its value.
    • If after the removal of num, the size of the left multiset decreases, delete the smallest integer from the mid multiset and insert it in the left multiset.
    • Similarly, for mid multiset, if the size decreases, delete the smallest integer from the right multiset and insert it in the mid multiset.
  • Define a function addInteger to add an integer to the current stream:
    • If the number of integers in the current stream(sum of the size of left, mid, right multiset) exceeds n, remove the integer at index pos%n.
    • Call the function add to insert the integer in the left, mid, or right multiset, based on its value.
  • Define the function calculateSpecialAverage to return the special average:
    • If the number of integers in the stream is less than N, then print -1.
    • Otherwise, print the average as (sum/(N – 2*K)).

Below is the implementation of the above approach:

C++




// C++ program for the above approach
  
#include <bits/stdc++.h>
using namespace std;
  
// Special Average class
class SpecialAverage {
public:
    // Three multisets to store the
    // smaller K larger K and the
    // remaining (n-2*k) integers
    multiset<int> left, mid, right;
  
    int n, k;
  
    // Stores the index of current
    // integer in running stream of
    // integers and the sum of integers
    // in mid multiset
    long pos, sum;
  
    // Array to store last n integers
    vector<int> v;
  
    // Constructor to initialize the
    // values of n and k and initialize
    // default values
    SpecialAverage(int nvalue, int kvalue)
    {
        n = nvalue;
        k = kvalue;
        pos = 0;
        sum = 0;
        for (int i = 0; i < n; i++)
            v.push_back(0);
    }
  
    // Add current integer in the
    // multiset left, mid or right
    // based on its value
    void add(int num)
    {
        // Firstly, insert num in the
        // left multiset
        left.insert(num);
  
        // Check if size of the left
        // multiset is greater than k
        if (left.size() > k) {
  
            // Stores the value of the
            // largest integer in the
            // left multiset
            int temp = *(prev(end(left)));
  
            // Insert temp in the
            // mid multiset
            mid.insert(temp);
  
            // Remove temp from the
            // left multiset
            left.erase(prev(end(left)));
  
            // Add the value of temp
            // to the current sum
            sum += temp;
        }
  
        // Check if the size of mid
        // multiset exceeds (n-2*k)
        if (mid.size() > (n - 2 * k)) {
  
            // Stores the value of the
            // largest integer in the
            // mid multiset
            int temp = *(prev(end(mid)));
  
            // Insert temp in the
            // right multiset
            right.insert(temp);
  
            // Remove temp from the
            // mid multiset
            mid.erase(prev(end(mid)));
  
            // Subtract the value of
            // temp from current sum
            sum -= temp;
        }
    }
  
    // Remove integer from the
    // multiset left, mid or right
    // based on its value
    void remove(int ele)
    {
  
        // If integer exists in the
        // left multiset
        if (ele <= *(left.rbegin()))
            left.erase(left.find(ele));
  
        // If integer exists in the
        // mid multiset
        else if (ele <= *(mid.rbegin())) {
  
            // Subtract the value of
            // integer from current sum
            sum -= ele;
            mid.erase(mid.find(ele));
        }
  
        // If integer exists in the
        // right multiset
        else
            right.erase(right.find(ele));
  
        // Balance all the multisets
        // left, right and mid check
        // if size of the left multiset
        // is less than k
        if (left.size() < k) {
  
            // Stores the value of
            // smallest integer
            // in mid multiset
            int temp = *(mid.begin());
  
            // Insert temp in the
            // left multiset
            left.insert(temp);
  
            // Remove temp from the
            // mid multiset
            mid.erase(mid.begin());
  
            // Subtract the value of
            // temp from current sum
            sum -= temp;
        }
  
        // Check if the size of mid
        // multiset becomes lesser
        // than (n-2*k)
        if (mid.size() < (n - 2 * k)) {
  
            // Stores the value of
            // smallest integer in
            // right multiset
            int temp = *(right.begin());
  
            // Insert temp in the
            // mid multiset
            mid.insert(temp);
  
            // Remove temp from the
            // right multiset
            right.erase(right.begin());
  
            // Add the value of temp
            // to the current sum
            sum += temp;
        }
    }
  
    // Function to add integer to
    // the current stream
    void addInteger(int num)
    {
  
        // Check if the total number
        // of elements in stream > n
        if (pos >= n)
  
            // Call the function to
            // remove  extra integer
            remove(v[pos % n]);
  
        // Insert the current integer
        // in the array v
        v[(pos++) % n] = num;
  
        // Call the function to add
        // the current integer in left,
        // mid or right multiset
        // based on its value
        add(num);
    }
  
    // Function to calculate the
    // special average
    int calculateSpecialAverage()
    {
        // Check if the total number
        // of elements is greater than
        // or equal to n
        if (pos >= n)
  
            // Return desired average
            return ((double)sum) / (n - 2 * k);
        return -1;
    }
};
  
// Function to process all the queries
void processQueries(int n, int k)
{
    // Create an object of the class
    SpecialAverage* avg
        = new SpecialAverage(n, k);
  
    // Add integer Query
    avg->addInteger(4);
    avg->addInteger(2);
  
    // Find average Query
    cout << avg->calculateSpecialAverage()
         << endl;
  
    // Add integer Query
    avg->addInteger(10);
  
    // Find average Query
    cout << avg->calculateSpecialAverage()
         << endl;
}
  
// Driver Code
int main()
{
    int N = 3, K = 1;
    processQueries(N, K);
  
    return 0;
}
Output:
-1
4

Time Complexity: O(log N) for addInteger() and O(1) for calculateSpecialAverage()
Auxiliary Space: O(N)

Attention reader! Don’t stop learning now. Get hold of all the important mathematical concepts for competitive programming with the Essential Maths for CP Course at a student-friendly price. To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.




My Personal Notes arrow_drop_up
Recommended Articles
Page :