📜  数组中滑动窗口的中位数|套装2

📅  最后修改于: 2021-04-28 16:37:18             🧑  作者: Mango

先决条件:基于策略的数据结构,滑动窗口技术。

给定一个由整数arr []和一个整数K组成的数组,任务是找到大小为K的每个窗口的中值,该窗口的大小从左开始,每次向右移动一个位置。

例子:

天真的方法:
解决该问题的最简单方法是遍历每个大小为K的窗口,并对窗口的元素进行排序,然后找到中间元素。将每个窗口的中间元素打印为中间值。
时间复杂度: O(N * KlogK)
辅助空间: O(K)

排序集方法:请参阅数组中滑动窗口的中位数以使用SortedSet解决问题。

有序集方法:
本文提供了一种使用基于策略的有序集数据结构解决问题的方法。
请按照以下步骤解决问题:

  1. 将第一个大小为K的窗口插入Ordered_set(保持排序顺序)。因此,此有序集合的中间元素是相应窗口的所需中间值。
  2. 中间元素可以通过O(logN)计算复杂度的find_by_order()方法获得。
  3. 通过删除上一个窗口的第一个元素并插入新元素,进入以下窗口。要从集合中删除任何元素,请使用order_by_key()在Ordered_Set中找到该元素的顺序,以O(logN)的计算复杂度获取结果,然后通过使用find_by_order在Ordered_Set中搜索其获得的顺序来擦除该元素。 ()方法。现在,为新窗口添加新元素。
  4. 对每个窗口重复上述步骤,并打印相应的中位数。

下面是上述方法的实现。

CPP
// C++ Program to implement the
// above approach
#include 
#include 
  
using namespace std;
using namespace __gnu_pbds;
  
// Policy based data structure
typedef tree, rb_tree_tag,
             tree_order_statistics_node_update>
    Ordered_set;
  
// Function to find and return the
// median of every window of size k
void findMedian(int arr[], int n,
                int k)
{
  
    Ordered_set s;
  
    for (int i = 0; i < k; i++)
        s.insert(arr[i]);
  
    if (k & 1) {
  
        // Value at index k/2
        // in sorted list.
        int ans = *s.find_by_order(k / 2);
  
        cout << ans << " ";
  
        for (int i = 0; i < n - k; i++) {
  
            // Erasing Element out of window.
            s.erase(s.find_by_order(
                s.order_of_key(
                    arr[i])));
  
            // Inserting newer element
            // to the window
            s.insert(arr[i + k]);
  
            // Value at index k/2 in
            // sorted list.
            ans = *s.find_by_order(k / 2);
  
            cout << ans << " ";
        }
        cout << endl;
    }
    else {
  
        // Getting the two middle
        // median of sorted list.
        float ans = ((float)*s.find_by_order(
                         (k + 1) / 2 - 1)
                     + (float)*s.find_by_order(k
                                               / 2))
                    / 2;
  
        printf("%.2f ", ans);
  
        for (int i = 0; i < n - k; i++) {
            s.erase(s.find_by_order(
                s.order_of_key(arr[i])));
  
            s.insert(arr[i + k]);
  
            ans = ((float)*s.find_by_order(
                       (k + 1) / 2 - 1)
                   + (float)*s.find_by_order(k
                                             / 2))
                  / 2;
  
            printf("%.2f ", ans);
        }
        cout << endl;
    }
}
  
// Driver Code
int main()
{
    int arr[] = { -1, 5, 13, 8, 2,
                  3, 3, 1 };
    int k = 3;
  
    int n = sizeof(arr)
            / sizeof(arr[0]);
    findMedian(arr, n, k);
  
    return 0;
}


输出:
5 8 8 3 3 3

时间复杂度: O(NlogK)
辅助空间: O(K)