Skip to content

Commit da70d63

Browse files
committed
feat: add solution 1825. Finding MK Average
1 parent d69aca1 commit da70d63

File tree

2 files changed

+378
-0
lines changed

2 files changed

+378
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# [1825. Finding MK Average](https://leetcode.com/problems/finding-mk-average)
2+
3+
## Description
4+
5+
<div class="elfjS" data-track-load="description_content"><p>You are given two integers, <code>m</code> and <code>k</code>, and a stream of integers. You are tasked to implement a data structure that calculates the <strong>MKAverage</strong> for the stream.</p>
6+
7+
<p>The <strong>MKAverage</strong> can be calculated using these steps:</p>
8+
9+
<ol>
10+
<li>If the number of the elements in the stream is less than <code>m</code> you should consider the <strong>MKAverage</strong> to be <code>-1</code>. Otherwise, copy the last <code>m</code> elements of the stream to a separate container.</li>
11+
<li>Remove the smallest <code>k</code> elements and the largest <code>k</code> elements from the container.</li>
12+
<li>Calculate the average value for the rest of the elements <strong>rounded down to the nearest integer</strong>.</li>
13+
</ol>
14+
15+
<p>Implement the <code>MKAverage</code> class:</p>
16+
17+
<ul>
18+
<li><code>MKAverage(int m, int k)</code> Initializes the <strong>MKAverage</strong> object with an empty stream and the two integers <code>m</code> and <code>k</code>.</li>
19+
<li><code>void addElement(int num)</code> Inserts a new element <code>num</code> into the stream.</li>
20+
<li><code>int calculateMKAverage()</code> Calculates and returns the <strong>MKAverage</strong> for the current stream <strong>rounded down to the nearest integer</strong>.</li>
21+
</ul>
22+
23+
<p>&nbsp;</p>
24+
<p><strong class="example">Example 1:</strong></p>
25+
26+
<pre><strong>Input</strong>
27+
["MKAverage", "addElement", "addElement", "calculateMKAverage", "addElement", "calculateMKAverage", "addElement", "addElement", "addElement", "calculateMKAverage"]
28+
[[3, 1], [3], [1], [], [10], [], [5], [5], [5], []]
29+
<strong>Output</strong>
30+
[null, null, null, -1, null, 3, null, null, null, 5]
31+
32+
<strong>Explanation</strong>
33+
<code>MKAverage obj = new MKAverage(3, 1);
34+
obj.addElement(3); // current elements are [3]
35+
obj.addElement(1); // current elements are [3,1]
36+
obj.calculateMKAverage(); // return -1, because m = 3 and only 2 elements exist.
37+
obj.addElement(10); // current elements are [3,1,10]
38+
obj.calculateMKAverage(); // The last 3 elements are [3,1,10].
39+
// After removing smallest and largest 1 element the container will be [3].
40+
// The average of [3] equals 3/1 = 3, return 3
41+
obj.addElement(5); // current elements are [3,1,10,5]
42+
obj.addElement(5); // current elements are [3,1,10,5,5]
43+
obj.addElement(5); // current elements are [3,1,10,5,5,5]
44+
obj.calculateMKAverage(); // The last 3 elements are [5,5,5].
45+
// After removing smallest and largest 1 element the container will be [5].
46+
// The average of [5] equals 5/1 = 5, return 5
47+
</code></pre>
48+
49+
<p>&nbsp;</p>
50+
<p><strong>Constraints:</strong></p>
51+
52+
<ul>
53+
<li><code>3 &lt;= m &lt;= 10<sup>5</sup></code></li>
54+
<li><code>1 &lt; k*2 &lt; m</code></li>
55+
<li><code>1 &lt;= num &lt;= 10<sup>5</sup></code></li>
56+
<li>At most <code>10<sup>5</sup></code> calls will be made to <code>addElement</code> and <code>calculateMKAverage</code>.</li>
57+
</ul>
58+
</div>
59+
60+
<p>&nbsp;</p>
61+
62+
## Solutions
63+
64+
**Solution: `Binary Search`**
65+
66+
- Time complexity: <em>O(nlogn)</em>
67+
- Space complexity: <em>O(n)</em>
68+
69+
<p>&nbsp;</p>
70+
71+
### **JavaScript**
72+
73+
```js
74+
/**
75+
* @param {number} m
76+
* @param {number} k
77+
*/
78+
const MKAverage = function (m, k) {
79+
this.m = m;
80+
this.k = k;
81+
this.queue = [];
82+
this.low = [];
83+
this.mid = [];
84+
this.high = [];
85+
this.midSum = 0;
86+
};
87+
88+
/**
89+
* @param {number} num
90+
* @return {void}
91+
*/
92+
MKAverage.prototype.addElement = function (num) {
93+
this.queue.push(num);
94+
95+
if (this.queue.length < this.m) {
96+
insert(this.mid, num);
97+
this.midSum += num;
98+
return;
99+
}
100+
101+
if (this.queue.length === this.m) {
102+
insert(this.mid, num);
103+
this.midSum += num;
104+
105+
while (this.low.length < this.k) {
106+
const smallestMid = this.mid.shift();
107+
108+
this.midSum -= smallestMid;
109+
insert(this.low, smallestMid);
110+
}
111+
112+
while (this.high.length < this.k) {
113+
const largestMid = this.mid.pop();
114+
115+
this.midSum -= largestMid;
116+
insert(this.high, largestMid);
117+
}
118+
119+
return;
120+
}
121+
122+
this.removeOldValue();
123+
124+
if (this.low.length && num <= this.low.at(-1)) {
125+
insert(this.low, num);
126+
const largestLow = this.low.pop();
127+
128+
insert(this.mid, largestLow);
129+
this.midSum += largestLow;
130+
} else if (this.high.length && num >= this.high[0]) {
131+
insert(this.high, num);
132+
const smallestHigh = this.high.shift();
133+
134+
insert(this.mid, smallestHigh);
135+
this.midSum += smallestHigh;
136+
} else {
137+
insert(this.mid, num);
138+
this.midSum += num;
139+
}
140+
141+
while (this.low.length < this.k) {
142+
const smallestMid = this.mid.shift();
143+
144+
this.midSum -= smallestMid;
145+
insert(this.low, smallestMid);
146+
}
147+
148+
while (this.low.length > this.k) {
149+
const largestLow = this.low.pop();
150+
151+
insert(this.mid, largestLow);
152+
this.midSum += largestLow;
153+
}
154+
155+
while (this.high.length < this.k) {
156+
const largestMid = this.mid.pop();
157+
158+
this.midSum -= largestMid;
159+
insert(this.high, largestMid);
160+
}
161+
162+
while (this.high.length > this.k) {
163+
const smallestHigh = this.high.shift();
164+
165+
insert(this.mid, smallestHigh);
166+
this.midSum += smallestHigh;
167+
}
168+
};
169+
170+
/**
171+
* @return {number}
172+
*/
173+
MKAverage.prototype.calculateMKAverage = function () {
174+
if (this.queue.length < this.m) return -1;
175+
176+
return Math.floor(this.midSum / (this.m - 2 * this.k));
177+
};
178+
179+
MKAverage.prototype.removeOldValue = function () {
180+
const old = this.queue.shift();
181+
182+
if (remove(this.low, old)) return;
183+
if (remove(this.high, old)) return;
184+
if (remove(this.mid, old)) {
185+
this.midSum -= old;
186+
}
187+
};
188+
189+
function insert(arr, val) {
190+
let left = 0,
191+
right = arr.length;
192+
193+
while (left < right) {
194+
const mid = Math.floor((left + right) / 2);
195+
196+
if (arr[mid] < val) left = mid + 1;
197+
else right = mid;
198+
}
199+
200+
arr.splice(left, 0, val);
201+
}
202+
203+
function remove(arr, val) {
204+
let left = 0,
205+
right = arr.length - 1;
206+
207+
while (left <= right) {
208+
const mid = Math.floor((left + right) / 2);
209+
210+
if (arr[mid] === val) {
211+
arr.splice(mid, 1);
212+
return true;
213+
} else if (arr[mid] < val) left = mid + 1;
214+
else right = mid - 1;
215+
}
216+
217+
return false;
218+
}
219+
220+
/**
221+
* Your MKAverage object will be instantiated and called as such:
222+
* var obj = new MKAverage(m, k)
223+
* obj.addElement(num)
224+
* var param_2 = obj.calculateMKAverage()
225+
*/
226+
```
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/**
2+
* @param {number} m
3+
* @param {number} k
4+
*/
5+
const MKAverage = function (m, k) {
6+
this.m = m;
7+
this.k = k;
8+
this.queue = [];
9+
this.low = [];
10+
this.mid = [];
11+
this.high = [];
12+
this.midSum = 0;
13+
};
14+
15+
/**
16+
* @param {number} num
17+
* @return {void}
18+
*/
19+
MKAverage.prototype.addElement = function (num) {
20+
this.queue.push(num);
21+
22+
if (this.queue.length < this.m) {
23+
insert(this.mid, num);
24+
this.midSum += num;
25+
return;
26+
}
27+
28+
if (this.queue.length === this.m) {
29+
insert(this.mid, num);
30+
this.midSum += num;
31+
32+
while (this.low.length < this.k) {
33+
const smallestMid = this.mid.shift();
34+
35+
this.midSum -= smallestMid;
36+
insert(this.low, smallestMid);
37+
}
38+
39+
while (this.high.length < this.k) {
40+
const largestMid = this.mid.pop();
41+
42+
this.midSum -= largestMid;
43+
insert(this.high, largestMid);
44+
}
45+
46+
return;
47+
}
48+
49+
this.removeOldValue();
50+
51+
if (this.low.length && num <= this.low.at(-1)) {
52+
insert(this.low, num);
53+
const largestLow = this.low.pop();
54+
55+
insert(this.mid, largestLow);
56+
this.midSum += largestLow;
57+
} else if (this.high.length && num >= this.high[0]) {
58+
insert(this.high, num);
59+
const smallestHigh = this.high.shift();
60+
61+
insert(this.mid, smallestHigh);
62+
this.midSum += smallestHigh;
63+
} else {
64+
insert(this.mid, num);
65+
this.midSum += num;
66+
}
67+
68+
while (this.low.length < this.k) {
69+
const smallestMid = this.mid.shift();
70+
71+
this.midSum -= smallestMid;
72+
insert(this.low, smallestMid);
73+
}
74+
75+
while (this.low.length > this.k) {
76+
const largestLow = this.low.pop();
77+
78+
insert(this.mid, largestLow);
79+
this.midSum += largestLow;
80+
}
81+
82+
while (this.high.length < this.k) {
83+
const largestMid = this.mid.pop();
84+
85+
this.midSum -= largestMid;
86+
insert(this.high, largestMid);
87+
}
88+
89+
while (this.high.length > this.k) {
90+
const smallestHigh = this.high.shift();
91+
92+
insert(this.mid, smallestHigh);
93+
this.midSum += smallestHigh;
94+
}
95+
};
96+
97+
/**
98+
* @return {number}
99+
*/
100+
MKAverage.prototype.calculateMKAverage = function () {
101+
if (this.queue.length < this.m) return -1;
102+
103+
return Math.floor(this.midSum / (this.m - 2 * this.k));
104+
};
105+
106+
MKAverage.prototype.removeOldValue = function () {
107+
const old = this.queue.shift();
108+
109+
if (remove(this.low, old)) return;
110+
if (remove(this.high, old)) return;
111+
if (remove(this.mid, old)) {
112+
this.midSum -= old;
113+
}
114+
};
115+
116+
function insert(arr, val) {
117+
let left = 0,
118+
right = arr.length;
119+
120+
while (left < right) {
121+
const mid = Math.floor((left + right) / 2);
122+
123+
if (arr[mid] < val) left = mid + 1;
124+
else right = mid;
125+
}
126+
127+
arr.splice(left, 0, val);
128+
}
129+
130+
function remove(arr, val) {
131+
let left = 0,
132+
right = arr.length - 1;
133+
134+
while (left <= right) {
135+
const mid = Math.floor((left + right) / 2);
136+
137+
if (arr[mid] === val) {
138+
arr.splice(mid, 1);
139+
return true;
140+
} else if (arr[mid] < val) left = mid + 1;
141+
else right = mid - 1;
142+
}
143+
144+
return false;
145+
}
146+
147+
/**
148+
* Your MKAverage object will be instantiated and called as such:
149+
* var obj = new MKAverage(m, k)
150+
* obj.addElement(num)
151+
* var param_2 = obj.calculateMKAverage()
152+
*/

0 commit comments

Comments
 (0)