/** LintCode.360.滑动窗口的中位数
* 题目:
* 给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,
* 找到数组中每个窗口内的中位数。(如果数组个数是偶数,则在该窗口排序数字后,返回第 N/2 个数字。)
* 样例:
* 对于数组 [1,2,7,8,5], 滑动大小 k = 3 的窗口时,返回 [2,7,7]
* 思路:
* 方案一: 最容易想到的方案是枚举,按顺序枚举每个滑动窗口的位置,计算出答案,为了修改的方便,
* 尽量将可能会改进的地方封装起来。
* 结果: TLE
* 方案二: 方案一由于过分追求松耦合导致运行开销过大。如果有一种数据结构能够像队列一样先进先出,又能像平衡二叉树一样
* 根节点即为中位数就好了。由于我们能够在O(1)时间找到该出队元素,因此可以使用multiset.
* 结果: Ac
*/
// 方案一: Time Limit Exceeded
class Solution
{
public:
/*
* @param nums: A list of integers
* @param k: An integer
* @return: The median of the element inside the window at each moving
*/
vector<int> medianSlidingWindow(vector<int> &nums, int k)
{
if (nums.empty() || k <= 0)
return {};
vector<int> result;
for (size_t i = 0; i + k <= nums.size(); ++i)
{
int leftElements = nums.size() - i; // 剩余元素个数
int selectedElements = min(k, leftElements); // 本次窗口中的元素个数
int median = GetMedian(nums.data() + i, selectedElements); // 获取窗口中的中位数
result.push_back(median);
}
return result;
}
int GetMedian(const int* window, int size)
{
int arr[size];
memcpy(arr, window, size * sizeof(*arr));
sort(arr, arr + size);
return arr[size-1 >> 1];
}
};
// 方案二: Accepted
class Solution
{
public:
/*
* @param nums: A list of integers
* @param k: An integer
* @return: The median of the element inside the window at each moving
*/
vector<int> medianSlidingWindow(vector<int> &nums, int k)
{
if (nums.empty() || k <= 0 || k > nums.size())
return {};
vector<int> result;
multiset<int> min_top_heap; // 4,5,6
multiset<int, greater<int> > max_top_heap; // 3,2,1
for (size_t i = 0; i < nums.size(); ++i)
{
// 插入
max_top_heap.insert(nums[i]);
int cur_window_size = max_top_heap.size() + min_top_heap.size();
// 调整
/// 移动
if (max_top_heap.size() > min_top_heap.size() + 1)
{
auto key_it = max_top_heap.begin();
min_top_heap.insert(*key_it);
max_top_heap.erase(key_it);
}
/// 交换
if (min_top_heap.size() && *max_top_heap.begin() > *min_top_heap.begin())
{
int max_top_val = *max_top_heap.begin();
int min_top_val = *min_top_heap.begin();
max_top_heap.erase(max_top_heap.begin());
min_top_heap.erase(min_top_heap.begin());
max_top_heap.insert(min_top_val);
min_top_heap.insert(max_top_val);
}
// 生成结果
if (cur_window_size == k)
{
result.push_back(*max_top_heap.begin());
/// 出队
int out_element = nums[i-k+1];
auto min_key_it = min_top_heap.find(out_element);
if (min_key_it != min_top_heap.end())
{
min_top_heap.erase(min_key_it);
}
else
{
auto max_key_it = max_top_heap.find(out_element);
if (max_key_it != max_top_heap.end())
max_top_heap.erase(max_key_it);
}
}
}
return result;
}
};
LintCode.360.滑动窗口的中位数
最新推荐文章于 2021-02-03 10:28:38 发布
本文介绍了一种计算滑动窗口中位数的有效方法。通过使用两个multiset实现动态平衡,可在数组上高效地计算不同窗口大小的中位数。文章对比了两种算法:一种是简单的枚举方法,另一种则是利用数据结构优化后的解决方案。
摘要由CSDN通过智能技术生成