JS 找出数据流中第K大元素

637 阅读2分钟

设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。

请实现 KthLargest 类:

KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。

int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

 

示例:

输入: ["KthLargest", "add", "add", "add", "add", "add"] [[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]] 输出: [null, 4, 5, 5, 8, 8]

解释: KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);

kthLargest.add(3); // return 4

kthLargest.add(5); // return 5

kthLargest.add(10); // return 5

kthLargest.add(9); // return 8

kthLargest.add(4); // return 8

一、常规解法:

需要找到数据流中第K大的元素,那么就首先需要排序,实现 KthLargest 类的构造,进行排序

var KthLargest = function(k, nums) {
    for (let j = 0; j < nums.length - 1; j++) {
        for (let i = 0; i < nums.length - 1; i++) {
        let current = nums[i]
        let next = nums[i + 1]
        if (current > next) {
            let temp = nums[i]
            nums[i] = nums[i + 1]
            nums[i + 1] = temp
        }
    }
    
  }
    this.k = k
    this.nums = nums

};

对象使用 add() 方法后,将添加数据 push 到 数据流最后,再次进行插入排序,仅仅针对最后一个元素插入即可,实现 add 方法:

KthLargest.prototype.add = function(val) {
    this.nums.push(val)
    let insertIndex = this.nums.length - 2
    while (insertIndex >= 0 && this.nums[insertIndex] > val) {
        this.nums[insertIndex + 1] = this.nums[insertIndex]
        insertIndex--
    }
    this.nums[insertIndex + 1] = val
    return this.nums[this.nums.length - this.k]
};

插入排序算法不再赘述,可以参考之前的文章: 插入排序

由于代码是从小到大排序的,那么最大的数据在 数据长度 - 插入下标,最终返回。

完整代码:

/**
 * @param {number} k
 * @param {number[]} nums
 */
var KthLargest = function(k, nums) {
    for (let j = 0; j < nums.length - 1; j++) {
        for (let i = 0; i < nums.length - 1; i++) {
        let current = nums[i]
        let next = nums[i + 1]
        if (current > next) {
            let temp = nums[i]
            nums[i] = nums[i + 1]
            nums[i + 1] = temp
        }
    }
    
  }
    this.k = k
    this.nums = nums

};

/** 
 * @param {number} val
 * @return {number}
 */
KthLargest.prototype.add = function(val) {
    this.nums.push(val)
    let insertIndex = this.nums.length - 2
    while (insertIndex >= 0 && this.nums[insertIndex] > val) {
        this.nums[insertIndex + 1] = this.nums[insertIndex]
        insertIndex--
    }
    this.nums[insertIndex + 1] = val
    return this.nums[this.nums.length - this.k]
};

结果:

image.png

二、JS 快捷解法:

由于 JS API 的特点,可以在思路保持不变的情况下使用 JS 独有的 API,达到快速方便解题的目的。

/**
 * @param {number} k
 * @param {number[]} nums
 */
var KthLargest = function(k, nums) {
  this.nums = nums.sort((a, b) => b - a)
  this.k = k
};

/** 
 * @param {number} val
 * @return {number}
 */
KthLargest.prototype.add = function(val) {
  this.nums.push(val)
  return this.nums.sort((a, b) => b - a)[this.k - 1]
};

结果:

image.png

比较两种解法:JS API 虽然代码量非常少,但是内存占用较大,且执行用时是常规解法的将近9倍,如果在实际问题中,需要考虑取舍!