Top K Frequent Elements

LeetCode July - Day 17

Problem Statement

Given a non-empty array of integers, return the k most frequent elements.

Example 1:

Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:

Input: nums = [1], k = 1
Output: [1]

Note:

  • You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
  • Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.
  • It’s guaranteed that the answer is unique, in other words the set of the top k frequent elements is unique.
  • You can return the answer in any order.

Inputs, Outputs, Constraints & Exceptions

  • I: number[] {nums}, number {k}
  • O: number[] {res}
  • C: at least nlogn fast, optimise
  • E: array size is 1

Code

// create a hashmap mapping num -> occurence
// sort this hashmap in descending order of occurence

// iterate through hashmap place first n elements in res array
// return res 

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
function topKFrequent(nums, k) {
  let occurences = new Map()
  for(let num of nums){
    if(occurences.has(num)) {
      occurences.set(num, occurences.get(num) + 1)
    } else {
      occurences.set(num, 1)
    }
  }

  let freq = Array.from(occurences).sort((a, b) => -a[1] + b[1])
  
  let res = []
  for(let i = 0; i < k; i++){
    res.push(freq[i][0])
  }

  return res
};

Code (using a Heap)

// JS has no in-built heap datastructure, so we'll have to implement one
class MaxHeap {
  constructor(){
    this.heap = [null]
  }

  get min(){
    return this.heap[1]
  }
  
  insert(item){
    let heap = this.heap
    heap.push(item)
    let curr = heap.length - 1
    
    while(curr > 1 && heap[curr].val > heap[Math.floor(curr/2)].val){
      [heap[curr], heap[Math.floor(curr/2)]] = [heap[Math.floor(curr/2)], heap[curr]]
      curr = Math.floor(curr/2)
    }
  }

  remove() {
    let heap = this.heap
    let biggest = heap[1]
    heap[1] = heap.pop()

    let curr = 1
    let left = 2 * curr
    let right = 2 * curr + 1

    while(heap[left] && heap[right] && heap[curr].val < Math.max(heap[left].val, heap[right].val)){
      if(heap[right].val < heap[left].val){
        [heap[curr], heap[left]] = [heap[left], heap[curr]]
        curr = left
      } else {
        [heap[curr], heap[right]] = [heap[right], heap[curr]]
        curr = right
      }
      left = 2 * curr
      right = 2 * curr + 1
    }

    if(heap[right] === undefined && heap[curr].val < heap[left]?.val){
      [heap[curr], heap[left]] = [heap[left], heap[curr]]
    }
     
    return biggest
  }
}

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
function topKFrequent(nums, k) {
  // build frequency map
  let freq = new Map()
  for(let num of nums){
    if(freq.has(num)){
      freq.set(num, freq.get(num) + 1)
    } else {
      freq.set(num, 1)
    }
  }

  let heap = new MaxHeap()
  for(let [k, v] of freq.entries()){
    heap.insert({key: k, val: v})
  }
 
  console.log(heap.heap)
  let res = []
  for(let i = 0; i < k; i++){
    res.push(Number(heap.remove().key))
  }

  return res
}

Code (using quickselect)

function topKFrequent(nums, k) {
  /*todo*/
}