📌  相关文章
📜  使用更新删除 K 个最小和最大元素后计算数组平均值的查询

📅  最后修改于: 2021-10-27 07:58:48             🧑  作者: Mango

给定两个正整数NK ,初始化一个空数组arr[]Q个以下两种类型的查询:

  • addInteger(x):在数组arr[] 中插入元素X。如果数组的大小变得大于N ,则从数组的开头删除元素。
  • calculateSpecialAverage():在去掉前K个最小和最大元素后求数组元素的平均值。如果数组的大小 小于N ,然后打印-1

任务是处理给定的查询并相应地打印结果。

例子:

方法:给定的问题可以通过使用多重集来解决。请按照以下步骤解决问题:

  • 初始化左、右三个多重集以存储K 个最小、 K 个最大和剩余的(N – 2*K) 个整数。
  • 声明一个大小为N的向量v来存储最后N 个整数。
  • 声明一个整数变量pos来跟踪当前索引和一个整数来存储中间多集中值的总和,这是计算(N – 2*K) 个整数的平均值所需的总和。
  • 定义一个函数add以根据其值在左、中多重集中插入一个整数。要在正确的多重集中插入整数,请执行以下步骤:
    • 最初,将整数插入多重集中。
    • 如果左侧多重集的大小超过k ,则从左侧多重集中删除最大的整数并将其插入中间多重集。
    • 如果mid multiset 的大小超过(n – 2*k) ,则从mid multiset 中删除最大的整数并将其插入到正确的multiset 中。
    • 中间多重集中删除和添加整数时保持正确的sum值,即如果从中间多重集中删除一个整数,则从总和减去它的值,类似地,如果在中间多重集中添加一个整数,将其值添加到sum ,以保持更新的总和值。
  • 声明一个函数remove从左、右中间多重集擦除整数。
    • 如果整数num 的值小于或等于左侧多重集中的最大整数,则从左侧多重集中查找并删除该整数,否则根据其值在中间右侧多重集中搜索它。
    • 如果删除num 后,大小 左边的多重集减少,从中删除最小的整数 中间多组并将其插入 多重集。
    • 同理,对于mid multiset,如果size变小了,删除最小的整数 正确的多重集并将其插入 中间多组。
  • 定义一个函数addInteger向当前流添加一个整数:
    • 如果当前流中的整数数量(左、中、右多重集的大小之和)超过n ,则删除索引pos%n处的整数。
    • 调用函数add插入整数 左、中多重集,基于其值。
  • 定义函数calculateSpecialAverage以返回特殊平均值:
    • 如果流中的整数数小于N ,则打印-1
    • 否则,将平均值打印为(sum/(N – 2*K))

下面是上述方法的实现:

C++
// C++ program for the above approach
  
#include 
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 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 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;
}


输出:
-1
4

时间复杂度: O(log N) for addInteger()和 O(1) for calculateSpecialAverage()
辅助空间: O(N)