[路飞]_前 K 个高频元素

173 阅读2分钟

347. 前 K 个高频元素

题目

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

示例1

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例2

输入: nums = [1], k = 1
输出: [1]

题解

哈希+排序

  • 统计数组中每一个元素出现的次数,将数据放在二维数组list中
  • 根据每个元素出现的次数排序,对二维数组list排序
  • 返回二维数组list前K个数据即可

代码

const topKFrequent = (nums, k) => {
  const map = {}
  nums.forEach((n) => {
    map[n] = (map[n] || 0) + 1
  })
  const list = []

  //遍历数据
  Object.keys(map).forEach((k) => {
    list.push([Number(k),map[k]])
  })
  list.sort((a,b)=>{
      return b[1] - a[1]
  })
  const result = list.slice(0,k)
  return result.map(v=>v[0])

 
}

堆排序

在哈希表+排序方法中对所有数据进行排序,这点可以利用堆排序优化,不理解堆的同学可以 点击我,带你了家JavaScript堆

  • 统计数组中每一个元素出现的次数,将数据放在二维数组list中
  • 将二维数组逐一放入小根堆中
  • 小根堆超出k个数据,删除堆顶数据
  • 返回小根堆中数据即可得带答案

代码

const topKFrequent = (nums, k) => {
  class Heap {
    constructor(compare) {
      this.list = [0]
      this.compare =
        typeof compare === 'function' ? compare : this.defaultCompare
    }

    defaultCompare(a, b) {
      return a > b
    }

    swap(x, y) {
      const t = this.list[x]
      this.list[x] = this.list[y]
      this.list[y] = t
    }
    isEmpty() {
      return this.list.length === 1
    }
    getSize() {
      return this.list.length - 1
    }
    top() {
      return this.list[1]
    }

    left(x) {
      return 2 * x
    }
    right(x) {
      return 2 * x + 1
    }
    parent(x) {
      return Math.floor(x / 2)
    }

    push(val) {
      // 新增数据,向堆尾添加
      this.list.push(val)

      this.up(this.list.length - 1)
    }
    // 上浮
    up(k) {
      const { list, parent, compare } = this
      while (k > 1 && compare(list[k], list[parent(k)])) {
        this.swap(parent(k), k)
        k = parent(k)
      }
    }
    pop() {
      const { list } = this
      if (list.length === 0) return null
      this.swap(1, list.length - 1)
      const top = list.pop()
      this.down(1)
      return top
    }

    down(k) {
      const { list, left, right, compare } = this
      const size = this.getSize()
      while (left(k) <= size) {
        let _left = left(k)
        if (right(k) <= size && compare(list[right(k)], list[_left])) {
          _left = right(k)
        }
        if (compare(list[k], list[_left])) return
        this.swap(k, _left)
        k = _left
      }
    }
  }
  const map = {}
  nums.forEach((n) => {
    map[n] = (map[n] || 0) + 1
  })
  //小根堆
  const heap = new Heap((a, b) => a[1] < b[1])
  //遍历数据
  Object.keys(map).forEach((key) => {
    heap.push([Number(key), map[key]])
    if (heap.getSize() > k) {
      heap.pop()
    }
  })
  //console.log('heap', heap)
  const size = heap.getSize()
  const result = []
  for (let i = 0; i < size; i++) {
    const top = heap.top()
    heap.pop()
    result.unshift(top[0])
  }
  return result
}