My issue is the logic to get the ordering correct--alphabetically. I just don't know what technique I can use to keep the values that are at most at the top and if they have the same occurrence and return the list in that alphabetic order.

Input: ["i", "love", "leetcode", "i", "love", "coding"], k = 2 Output: ["i", "love"] Explanation: "i" and "love" are the two most frequent words. Note that "i" comes before "love" due to a lower alphabetical order.

var topKFrequent = function(words, k) {
    // Intialize a map to obtain our frequency of words
    const wordCount = {}; 
    for (const word of words)  {
        wordCount[word] = (wordCount[word] || 0) + 1
    }
    const priority = new PriorityQueue();
    
    for (const word in wordCount) {
        priority.enqueue(word, wordCount[word])
        if (priority.values.length > k) {
            priority.dequeue();
        }
    }
    const result = []; 
    for (const node of priority.values) {
        result.push(node.val)
    }
  
    return result; 
};


function stringCompare(word1, word2) {
    if (word1.priority === word2.priority) return word2.val.localeCompare(word1.val); 
    return word1.priority - word2.priority; 
}



class PriorityQueue {
  constructor() {
    this.values = []; 
  }

  enqueue(val, priority) {
    let node = new Node(val, priority);
    this.values.push(node); 
    this.bubbleUp();  
  }

  bubbleUp() {
    let currentIdx = this.values.length - 1
    const child = this.values[currentIdx]; 
    while (currentIdx > 0) {
      let parentIdx = Math.floor((currentIdx - 1) / 2); 
      const parent = this.values[parentIdx]; 
      if (child.priority >= parent.priority) break; 
      // Swap 
      this.values[currentIdx] = parent; 
      this.values[parentIdx] = child; 
      currentIdx = parentIdx; 
    }
  }

  dequeue() {
    const min = this.values[0]; 
    const end = this.values.pop(); 
    if (this.values.length > 0) {
      this.values[0] = end; 
      this.sinkDown(); 
    }
    return min; 
  }



  sinkDown() {
    let idx = 0; 
    const currentElement = this.values[0]; 
    const { length } = this.values; 

    while (true) {
      let leftChildIdx = 2 * idx + 1; 
      let rightChildIdx = 2 * idx + 2; 
      let leftChild, rightChild; 
      let toSwapIdx = null; 

      if (leftChildIdx < length) {
        leftChild = this.values[leftChildIdx]; 
        if (leftChild.priority < currentElement.priority) {
          toSwapIdx = leftChildIdx; 
        }
      }

      if (rightChildIdx < length) {
        rightChild = this.values[rightChildIdx]; 
        if (
          (toSwapIdx === null && rightChild.priority < currentElement.priority) || 
          (toSwapIdx !== null && rightChild.priority < leftChild.priority)
          ) {
            toSwapIdx = rightChildIdx; 
        }
      }
      if (toSwapIdx === null) break;// break while loop condition
      this.values[idx] = this.values[toSwapIdx]; 
      this.values[toSwapIdx] = currentElement; 
      idx = toSwapIdx; 
    }
  }



}


class Node {
  constructor(val, priority) {
    this.val = val; 
    this.priority = priority; 
  }
}

1

There are 1 best solutions below

0
On

You can use array methods including .filter(), .map(), etc to simplify your code. I hope this solution meets the requirements.


My solution

function myFunction(words, k) {
  return [...new Set(words.map(word => words.filter(e => e === word)).sort((a, b) => b.length - a.length).filter(e => e.length > 1).map(e => e[0]))]
            .slice(0, k)
            .sort();
}

console.log(myFunction(["love", "i", "leetcode", "love", "i", "coding"], 2));
// Output: ["i", "love"] 

console.log(myFunction(["i", "need", "you", "i", "love", "you", "i", "hate", "you"], 3));
// Output: ["i", you"] 

console.log(myFunction(["if", "else if", "else", "if", "if", "if", "else"], 4));
// Output: ["else", "if"]

console.log(myFunction(["if", "else if", "else", "if", "if", "if", "else"], 2));
// Output: ["else", "if"]

console.log(myFunction(["if", "else if", "else", "if", "if", "if", "else"], 2));
// Output: ["else", "if"]


See step by step

The above solution is a single-line of code, which might not be readable. I have split it to make it understandable.

function myFunction(words, k) {
  console.log("--- Start ---");
  let arr = [];
  
  arr = words.map(word => words.filter(e => e === word));
  console.log(`Step 1: ${arr}`);
  
  arr = arr.sort((a, b) => b.length - a.length);
  console.log(`Step 2: ${arr}`);
  
  arr = arr.filter(e => e.length > 1);
  console.log(`Step 3: ${arr}`); 
  
  arr =  arr.map(e => e[0]);
  console.log(`Step 4: ${arr}`);
  
  arr = [...new Set(arr)]; 
  console.log(`Step 5: ${arr}`);
  
  arr = arr.slice(0, k);
  console.log(`Step 6: ${arr}`);
  
  arr = arr.sort();
  console.log(`Step 7: ${arr}`);
  
  console.log("--- Completed ---");
  return arr
}

console.log(myFunction(["love", "i", "leetcode", "love", "i", "coding"], 2));
// Output: ["i", "love"] 

console.log(myFunction(["i", "need", "you", "i", "love", "you", "i", "hate", "you"], 3));
// Output: ["i", you"] 

console.log(myFunction(["if", "else if", "else", "if", "if", "if", "else"], 4));
// Output: ["else", "if"]

console.log(myFunction(["if", "else if", "else", "if", "if", "if", "else"], 2));
// Output: ["else", "if"]

console.log(myFunction(["if", "else if", "else", "if", "if", "if", "else"], 2));
// Output: ["else", "if"]