dcddc

西米大人的博客

0%

滑动窗口的中位数

题目描述

给定一个包含 n 个整数的数组,和一个大小为 k 的滑动窗口,从左到右在数组中滑动这个窗口,找到数组中每个窗口内的最大值
样例
对于数组 [1,2,7,8,5], 滑动大小 k = 3 的窗口时,返回 [2,7,7]
最初,窗口的数组是这样的:
[ | 1,2,7 | ,8,5] , 返回中位数 2;
接着,窗口继续向前滑动一次。
[1, | 2,7,8 | ,5], 返回中位数 7;
接着,窗口继续向前滑动一次。
[1,2, | 7,8,5 | ], 返回中位数 7;

思路

1、构造一个大顶堆一个小顶堆
2、对前k个元素,将小于num[0]的元素放入大顶堆,大于num[0]的元素放入小顶堆
3、平衡小顶堆和大顶堆元素的数目后,得到中位数
4、从堆中删除nums[0]
5、每次根据后一个元素大小决定其放入的堆,平衡两个堆的数目后,得到中位数
6、删除旧元素后,回到第五步,直到访问完所有元素

堆中增加元素lgn复杂度,遍历数组的复杂度为n,所以时间复杂度:nlgn

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
public class Solution {  
public class minComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b){
if(a > b) return 1;
else if(a == b) return 0;
else return -1;
}
}
public class maxComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b){
if(a > b) return -1;
else if(a == b) return 0;
else return 1;
}
}
/**
* @param nums: A list of integers.
* @return: The median of the element inside the window at each moving.
*/
public ArrayList<Integer> medianSlidingWindow(int[] nums, int k) {
// write your code here
ArrayList<Integer> res = new ArrayList<>();
// exception
if(k == 1) {
Integer[] ints = new Integer[nums.length];
for(int i = 0; i < nums.length; i++) {
ints[i] = nums[i];
}
return new ArrayList<Integer>(Arrays.asList(ints));
}
if(k == 2) {
for(int i = 0; i < nums.length-1; i++) {
res.add(Math.min(nums[i], nums[i+1]));
}
return res;
}

// init heap
PriorityQueue<Integer> MaxHeap = new PriorityQueue<>(new maxComparator());
PriorityQueue<Integer> MinHeap = new PriorityQueue<>(new minComparator());
MaxHeap.add(nums[0]);
for(int i = 1; i < k; i++) {
if(nums[i] > nums[0]) {
MinHeap.add(nums[i]);
}else {
MaxHeap.add(nums[i]);
}
}
if(k % 2 == 1) {
if(MinHeap.size() > MaxHeap.size()) {
while(( MinHeap.size()-MaxHeap.size() ) != 1) {
MaxHeap.add(MinHeap.poll());
}
res.add(MinHeap.peek());
// 删除旧元素,并使得小堆和大堆平衡
MaxHeap.add(MinHeap.poll());
MaxHeap.remove(nums[0]);
}else {
while( ( MaxHeap.size()-MinHeap.size() ) != 1 ) {
MinHeap.add(MaxHeap.poll());
}
res.add(MaxHeap.peek());
// 删除旧元素,并使得小堆和大堆平衡
MinHeap.add(MaxHeap.poll());
MinHeap.remove(nums[0]);
}
}else {
if(MaxHeap.size() > MinHeap.size()) {
while(MaxHeap.size() != MinHeap.size()) {
MinHeap.add(MaxHeap.poll());
}
res.add(MaxHeap.peek());
MinHeap.remove(nums[0]);
}else if(MaxHeap.size() < MinHeap.size()) {
while( MaxHeap.size() != MinHeap.size() ){
MaxHeap.add(MinHeap.poll());
}
res.add(MaxHeap.peek());
MaxHeap.remove(nums[0]);
}else {
res.add(MaxHeap.peek());
MaxHeap.remove(nums[0]);
}
}

// 寻找第k个数字之后的中位数
for(int i = k; i < nums.length; i++) {
// 新数入堆
if(nums[i] > MinHeap.peek()) {
MinHeap.add(nums[i]);
}else {
MaxHeap.add(nums[i]);
}
// 分K为偶数奇数找到中位数
if(k % 2 == 1) {
if(MinHeap.size() > MaxHeap.size()) {
// 使大小堆数目平衡
while(( MinHeap.size()-MaxHeap.size() ) != 1) {
MaxHeap.add(MinHeap.poll());
}
// 找到中位数
res.add(MinHeap.peek());
}else {
// 使大小堆数目平衡
while( ( MaxHeap.size()-MinHeap.size() ) != 1 ) {
MinHeap.add(MaxHeap.poll());
}
// 找到中位数
res.add(MaxHeap.peek());
}
}else {
if(MaxHeap.size() > MinHeap.size()) {
// 使大小堆数目平衡
while(MaxHeap.size() != MinHeap.size()) {
MinHeap.add(MaxHeap.poll());
}
// 找到中位数
res.add(MaxHeap.peek());
}else if(MaxHeap.size() < MinHeap.size()) {
// 使大小堆数目平衡
while( MaxHeap.size() != MinHeap.size() ){
MaxHeap.add(MinHeap.poll());
}
// 找到中位数
res.add(MaxHeap.peek());
}else {
// 找到中位数
res.add(MaxHeap.peek());
}
}
// 丢掉最左边的数
if(nums[i-k+1] >= MinHeap.peek()) {
MinHeap.remove(nums[i-k+1]);
}else {
MaxHeap.remove(nums[i-k+1]);
}
}
return res;
}

public static void main(String args[]) {
Solution solution = new Solution();
ArrayList<Integer> list = solution.medianSlidingWindow(new int[]{1,2,3,5,3,5,1,2,7,4,3,9,6}, 1);
for(int num : list) {
System.out.print(num);
}
}
}

考差点