703 数据流中的第K大元素
// 30.43% 好像是5% orz
/**
* @param {number} k
* @param {number[]} nums
*/
var KthLargest = function(k, nums) {
this.sortedNums = nums.sort((a, b) => b - a);
this.kmax = this.sortedNums[k-1]
this.k = k
};
/**
* @param {number} val
* @return {number}
*/
KthLargest.prototype.add = function(val) {
if (!this.kmax) {
this.sortedNums.push(val)
this.sortedNums.sort((a, b) => b - a)
this.kmax = this.sortedNums[this.k-1];
return this.kmax
}
if (val <= this.kmax) return this.kmax
let tmp = [], flag = true
let i = 0, j = 0;
// console.log(this.k, this.sortedNums[j])
while (i < this.k){
if (val > this.sortedNums[j] && flag){
tmp[i++] = val
flag = false
}else{
tmp[i++] = this.sortedNums[j++]
}
}
this.sortedNums = tmp
this.kmax = this.sortedNums[this.k-1]
return this.kmax
};
/**
* Your KthLargest object will be instantiated and called as such:
* var obj = new KthLargest(k, nums)
* var param_1 = obj.add(val)
*/
因为只要第k大的元素,所以,只要保存k个最大的元素,每次返回最小的那个就可以了。每次add操作先跟最小的元素判断,如果比最小的还小,就直接返回当前最小的这个数即可。否则重新调整这k个元素。因此要做的是维护一个最小值,并且动态调整。可以用最小堆来做,最小的永远都是堆顶元素,如果新add的元素小于堆顶,直接返回堆顶元素。否则将堆顶元素直接替换成新元素,再从上到下进行调整。而初始化堆的时候,则从下往上调整保证堆顶的最小。
// 144ms 95.08% 44.7mb 44.12%
var KthLargest = function(k, nums) {
this.k = k
this.knums = []
this.swap = function(arr, i, j){
let tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
}
for (let i of nums){
this.add(i)
}
};
KthLargest.prototype.add = function(val) {
let len = this.knums.length;
if (len === 0){
this.knums[1] = val
return this.knums[1]
}
if (len-1 < this.k){ // 因为第0个元素不用,从第一个元素开始存
let cur = len
this.knums[cur] = val
let parent = cur%2 === 0 ? cur/2 : (cur-1)/2
while(this.knums[parent] > this.knums[cur]){
this.swap(this.knums, parent, cur)
cur = parent
parent = cur%2 === 0 ? cur/2 : (cur-1)/2
}
}else{
if (this.knums[1] >= val){
return this.knums[1]
}
this.knums[1] = val
let cur = 1
while(this.knums[cur*2] !== undefined){
let min = cur*2
if (this.knums[cur*2 + 1] !== undefined && this.knums[cur*2] > this.knums[cur*2 + 1]){
min = cur*2+1
}
if (this.knums[cur] > this.knums[min]){
this.swap(this.knums, min, cur)
cur = min
}else{
break
}
}
}
return this.knums[1]
};
// let k = 3;
// let arr = [4,5,8,2];
// let kthLargest = new KthLargest(k, arr);
// console.log(kthLargest.add(3)); // returns 4
// console.log(kthLargest.add(5)); // returns 5
// console.log(kthLargest.add(10)); // returns 5
// console.log(kthLargest.add(9)); // returns 8
// console.log(kthLargest.add(4)); // returns 8
// let k = 1;
// let arr = [];
// let kthLargest = new KthLargest(k, arr);
// console.log(kthLargest.add(-3)); // returns -3
// console.log(kthLargest.add(-2)); // returns -2
// console.log(kthLargest.add(-4)); // returns -2
// console.log(kthLargest.add(0)); // returns 0
// console.log(kthLargest.add(4)); // returns 4
// let k = 2;
// let arr = [0];
// let kthLargest = new KthLargest(k, arr);
// console.log(kthLargest.add(-1)); // returns -1
// console.log(kthLargest.add(1)); // returns 0
// console.log(kthLargest.add(-2)); // returns 0
// console.log(kthLargest.add(-4)); // returns 0
// console.log(kthLargest.add(3)); // returns 1
239 滑动窗口最大值
// 96ms 97.64% 41.1MB 88.14%
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function(nums, k) {
if (!nums) return []
let window = [], res = []
for (let i = 0; i < nums.length; i++){
if (window[0] !== undefined && i >= k + window[0]){
window.shift()
}
while(window.length > 0 && nums[window[window.length-1]] <= nums[i]){
window.pop()
}
window.push(i)
if (window[0] !== undefined && i >= k-1){
res.push(nums[window[0]])
}
}
return res
};
// console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)) // [ 3, 3, 5, 5, 6, 7 ]
// console.log(maxSlidingWindow([7, 2, 4], 2)) // [ 7, 4 ]
window用来保存在当前窗口中的元素索引,res保存每次移动的最大值结果。while循环保证当前窗口中的最左边也就是第一个元素一定是最大值元素,第一个if:当元素移出窗口时,直接移除掉该元素。性能惊人。