[路飞]LeetCode.215]数组中第K大个元素、【Leetcode.offer40】最小的K个数、【Leetcode.1046】最后一块石头的重量、Lee

194 阅读2分钟

基于前面的优先队列的构建

[LeetCode.215]数组中第K大个元素

解析

  • 第K大个元素,我们可以定义一个小顶堆, 因为最小值是跟节点,每次都可以pop出去
  • 保持顶堆元素大小是K, 当小于K的时候 逐个push, 当只有大于我们的根顶元素值的时候再push,然后把 根顶元素pop出去, 最终我们的根顶就是第K大
// 定义小顶堆的值比较方法
function compare(a, b) {
    return a < b
}

function findKthLargest(nums, k) {
    const heap = new Heap(compare)
    for (let i = 0; i < nums.length; i++) {
        if(heap.size() < k || heap.top() < nums[i]) {
            heap.push(nums[i])
            
            if (heap.size() > k) {
                heap.pop()
            }
            
        }
    }
    
    return heap.top()
}

【Leetcode.offer40】最小的K个数

解析

  • 因为是取最小的K个数,所以定义大顶堆,先把沾满K个元素,小于根顶元素的时候再替换
var getLeastNumbers = function(arr, k) {
  // 默认是a > b 大顶堆
  const heap = new Heap()

  for (let i = 0; i < arr.length; i++) {
    if (heap.size() < k || arr[i] < heap.top()) {
      heap.push(arr[i])
      if (heap.size() > k) {
        heap.pop()
      }
    }
  }
  return heap.data
};

【Leetcode。1046】最后一块石头的重量

题目

有一堆石头,每块石头的重量都是正整数。

每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎; 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。 最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。

解析

  • 更具题意需要一个大顶堆来去消减石头
  • 每次取出两块石头对比即 pop() 两次
  • 终止配石头的条件是 剩余一块时候或者没有石头的时候
var lastStoneWeight = function(stones) {
    // 创建一个大顶堆
    const heap = new Heap()
    // 把石头添加到堆里
    for (let i = 0; i < stones.length;i++) {
        heap.push(stones[i])
    }
    // 配石头的边界条件
    while(heap.size() > 1) {
        const f = heap.top()
        heap.pop()
        const s = heap.top()
        heap.pop()
        // 如果碰撞后剩余石头则在加入堆中
        if (f - s > 0) {
            heap.push(f - s)
        }
    }
    // return 出最后块石头的重量或者空的时候0
    return heap.size() ? heap.top() : 0
}

【Leetcode.703数据流中第K大元素】

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

请实现 KthLargest 类:

KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。 int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

解析

  • 和数组中第K大元素差不离, 构建小顶堆, push的条件也是一样
// 小顶堆的比较方法
function compare(a, b) {
    return a < b
}

var KthLargest = function(k, nums) {
  this.heap = new Heap(compare)
  this.k = k

  for (let i = 0; i < nums.length; i++) {
    this.add(nums[i])
  }
};

KthLargest.prototype.add = function(val) {
  if (this.heap.size() < this.k || this.heap.top() < val) {
    this.heap.push(val)
    if (this.heap.size() > this.k) {
      this.heap.pop()
    }
  }

  return this.heap.top()
};

总结

  • 堆(优先队列)的思路: 看似数组 处理逻辑当成完全二叉树
  • 最大最小的问题,保持堆的大小,定义好条件