列表

详情


480. 滑动窗口中位数

中位数是有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。

例如:

给你一个数组 nums,有一个长度为 k 的窗口从最左端滑动到最右端。窗口中有 k 个数,每次窗口向右移动 1 位。你的任务是找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。

 

示例:

给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。

窗口位置                      中位数
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7      -1
 1  3 [-1  -3  5] 3  6  7      -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6

 因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]

 

提示:

相似题目

数据流的中位数

原站题解

去查看

class Solution {
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
}
};
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

cpp 解法, 执行用时: 108 ms, 内存消耗: 34.1 MB, 提交时间: 2023-06-13 14:29:20

class Solution {
public:
priority_queue<int> small;
priority_queue<int, vector<int>, greater<int> > big;
unordered_map<int, int> mp;
double get(int& k){
if(k%2) return small.top();
else return ((long long)small.top()+big.top())*0.5;
}
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
for(int i = 0; i < k; i++){small.push(nums[i]);};
for(int i = 0; i < k / 2; i++){big.push(small.top()); small.pop();}
vector<double> ans{get(k)};
for(int i = k; i < nums.size(); i++){
int balance = 0;
int l = nums[i-k];
mp[l]++;
if(!small.empty() && l<=small.top()){balance--;}
else {balance++;}
if(!small.empty() && nums[i] <= small.top()){
small.push(nums[i]);
balance++;
}
else{
big.push(nums[i]);
balance--;
}
if(balance>0){
big.push(small.top());
small.pop();
}
if(balance<0){
small.push(big.top());
big.pop();
}
while(!small.empty() && mp[small.top()]>0){
mp[small.top()]--;
small.pop();
}
while(!big.empty() && mp[big.top()]>0){
mp[big.top()]--;
big.pop();
}
ans.push_back(get(k));
}
return ans;
}
};

golang 解法, 执行用时: 80 ms, 内存消耗: 11.3 MB, 提交时间: 2023-06-13 14:28:53

type hp struct {
sort.IntSlice
size int
}
func (h *hp) Push(v interface{}) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() interface{} { a := h.IntSlice; v := a[len(a)-1]; h.IntSlice = a[:len(a)-1]; return v }
func (h *hp) push(v int) { h.size++; heap.Push(h, v) }
func (h *hp) pop() int { h.size--; return heap.Pop(h).(int) }
func (h *hp) prune() {
for h.Len() > 0 {
num := h.IntSlice[0]
if h == small {
num = -num
}
if d, has := delayed[num]; has {
if d > 1 {
delayed[num]--
} else {
delete(delayed, num)
}
heap.Pop(h)
} else {
break
}
}
}
var delayed map[int]int
var small, large *hp
func medianSlidingWindow(nums []int, k int) []float64 {
delayed = map[int]int{} // key value
small = &hp{} //
large = &hp{} //
makeBalance := func() {
// small large 使
if small.size > large.size+1 { // small large 2
large.push(-small.pop())
small.prune() // small prune
} else if small.size < large.size { // large small 1
small.push(-large.pop())
large.prune() // large prune
}
}
insert := func(num int) {
if small.Len() == 0 || num <= -small.IntSlice[0] {
small.push(-num)
} else {
large.push(num)
}
makeBalance()
}
erase := func(num int) {
delayed[num]++
if num <= -small.IntSlice[0] {
small.size--
if num == -small.IntSlice[0] {
small.prune()
}
} else {
large.size--
if num == large.IntSlice[0] {
large.prune()
}
}
makeBalance()
}
getMedian := func() float64 {
if k&1 > 0 {
return float64(-small.IntSlice[0])
}
return float64(-small.IntSlice[0]+large.IntSlice[0]) / 2
}
for _, num := range nums[:k] {
insert(num)
}
n := len(nums)
ans := make([]float64, 1, n-k+1)
ans[0] = getMedian()
for i := k; i < n; i++ {
insert(nums[i])
erase(nums[i-k])
ans = append(ans, getMedian())
}
return ans
}

python3 解法, 执行用时: 268 ms, 内存消耗: 30.9 MB, 提交时间: 2023-06-13 14:28:37

class DualHeap:
def __init__(self, k: int):
# python 使
self.small = list()
#
self.large = list()
# key value
self.delayed = collections.Counter()
self.k = k
# small large
self.smallSize = 0
self.largeSize = 0
# heap ·
def prune(self, heap: List[int]):
while heap:
num = heap[0]
if heap is self.small:
num = -num
if num in self.delayed:
self.delayed[num] -= 1
if self.delayed[num] == 0:
self.delayed.pop(num)
heapq.heappop(heap)
else:
break
# small large 使
def makeBalance(self):
if self.smallSize > self.largeSize + 1:
# small large 2
heapq.heappush(self.large, -self.small[0])
heapq.heappop(self.small)
self.smallSize -= 1
self.largeSize += 1
# small prune
self.prune(self.small)
elif self.smallSize < self.largeSize:
# large small 1
heapq.heappush(self.small, -self.large[0])
heapq.heappop(self.large)
self.smallSize += 1
self.largeSize -= 1
# large prune
self.prune(self.large)
def insert(self, num: int):
if not self.small or num <= -self.small[0]:
heapq.heappush(self.small, -num)
self.smallSize += 1
else:
heapq.heappush(self.large, num)
self.largeSize += 1
self.makeBalance()
def erase(self, num: int):
self.delayed[num] += 1
if num <= -self.small[0]:
self.smallSize -= 1
if num == -self.small[0]:
self.prune(self.small)
else:
self.largeSize -= 1
if num == self.large[0]:
self.prune(self.large)
self.makeBalance()
def getMedian(self) -> float:
return float(-self.small[0]) if self.k % 2 == 1 else (-self.small[0] + self.large[0]) / 2
class Solution:
def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
dh = DualHeap(k)
for num in nums[:k]:
dh.insert(num)
ans = [dh.getMedian()]
for i in range(k, len(nums)):
dh.insert(nums[i])
dh.erase(nums[i - k])
ans.append(dh.getMedian())
return ans

java 解法, 执行用时: 46 ms, 内存消耗: 54.1 MB, 提交时间: 2023-06-13 14:28:20

class Solution {
public double[] medianSlidingWindow(int[] nums, int k) {
DualHeap dh = new DualHeap(k);
for (int i = 0; i < k; ++i) {
dh.insert(nums[i]);
}
double[] ans = new double[nums.length - k + 1];
ans[0] = dh.getMedian();
for (int i = k; i < nums.length; ++i) {
dh.insert(nums[i]);
dh.erase(nums[i - k]);
ans[i - k + 1] = dh.getMedian();
}
return ans;
}
}
class DualHeap {
//
private PriorityQueue<Integer> small;
//
private PriorityQueue<Integer> large;
// key value
private Map<Integer, Integer> delayed;
private int k;
// small large
private int smallSize, largeSize;
public DualHeap(int k) {
this.small = new PriorityQueue<Integer>(new Comparator<Integer>() {
public int compare(Integer num1, Integer num2) {
return num2.compareTo(num1);
}
});
this.large = new PriorityQueue<Integer>(new Comparator<Integer>() {
public int compare(Integer num1, Integer num2) {
return num1.compareTo(num2);
}
});
this.delayed = new HashMap<Integer, Integer>();
this.k = k;
this.smallSize = 0;
this.largeSize = 0;
}
public double getMedian() {
return (k & 1) == 1 ? small.peek() : ((double) small.peek() + large.peek()) / 2;
}
public void insert(int num) {
if (small.isEmpty() || num <= small.peek()) {
small.offer(num);
++smallSize;
} else {
large.offer(num);
++largeSize;
}
makeBalance();
}
public void erase(int num) {
delayed.put(num, delayed.getOrDefault(num, 0) + 1);
if (num <= small.peek()) {
--smallSize;
if (num == small.peek()) {
prune(small);
}
} else {
--largeSize;
if (num == large.peek()) {
prune(large);
}
}
makeBalance();
}
// heap
private void prune(PriorityQueue<Integer> heap) {
while (!heap.isEmpty()) {
int num = heap.peek();
if (delayed.containsKey(num)) {
delayed.put(num, delayed.get(num) - 1);
if (delayed.get(num) == 0) {
delayed.remove(num);
}
heap.poll();
} else {
break;
}
}
}
// small large 使
private void makeBalance() {
if (smallSize > largeSize + 1) {
// small large 2
large.offer(small.poll());
--smallSize;
++largeSize;
// small prune
prune(small);
} else if (smallSize < largeSize) {
// large small 1
small.offer(large.poll());
++smallSize;
--largeSize;
// large prune
prune(large);
}
}
}

cpp 解法, 执行用时: 108 ms, 内存消耗: 33 MB, 提交时间: 2023-06-13 14:28:05

// +
class DualHeap {
private:
//
priority_queue<int> small;
//
priority_queue<int, vector<int>, greater<int>> large;
// key value
unordered_map<int, int> delayed;
int k;
// small large
int smallSize, largeSize;
public:
DualHeap(int _k): k(_k), smallSize(0), largeSize(0) {}
private:
// heap
template<typename T>
void prune(T& heap) {
while (!heap.empty()) {
int num = heap.top();
if (delayed.count(num)) {
--delayed[num];
if (!delayed[num]) {
delayed.erase(num);
}
heap.pop();
}
else {
break;
}
}
}
// small large 使
void makeBalance() {
if (smallSize > largeSize + 1) {
// small large 2
large.push(small.top());
small.pop();
--smallSize;
++largeSize;
// small prune
prune(small);
}
else if (smallSize < largeSize) {
// large small 1
small.push(large.top());
large.pop();
++smallSize;
--largeSize;
// large prune
prune(large);
}
}
public:
void insert(int num) {
if (small.empty() || num <= small.top()) {
small.push(num);
++smallSize;
}
else {
large.push(num);
++largeSize;
}
makeBalance();
}
void erase(int num) {
++delayed[num];
if (num <= small.top()) {
--smallSize;
if (num == small.top()) {
prune(small);
}
}
else {
--largeSize;
if (num == large.top()) {
prune(large);
}
}
makeBalance();
}
double getMedian() {
return k & 1 ? small.top() : ((double)small.top() + large.top()) / 2;
}
};
class Solution {
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
DualHeap dh(k);
for (int i = 0; i < k; ++i) {
dh.insert(nums[i]);
}
vector<double> ans = {dh.getMedian()};
for (int i = k; i < nums.size(); ++i) {
dh.insert(nums[i]);
dh.erase(nums[i - k]);
ans.push_back(dh.getMedian());
}
return ans;
}
};

上一题