0

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; 
  }
}
Woody P Lucas
  • 77
  • 1
  • 5
  • Don't write so much code for this simple task. Step 1: iterate the array recursively to extract the mode every time until we have iterated k times. Step 2 sort the collection array. Done – Seyi Shoboyejo Mar 03 '21 at 17:02
  • I know, but I am trying to practice implementation of Priority Queue's – Woody P Lucas Mar 03 '21 at 17:05
  • Okay I am looking at your code now. And there appears to be an issue with bubbleUp. You should not be swapping child and parent (you might be moving parent back too much). You have to splice the values array instead. If you need to keep length constant you can then reset the array length to the constant value. Fix that bug first and let's see... – Seyi Shoboyejo Mar 03 '21 at 17:45
  • Again if you really like efficiency, the part where you do 'object.property || 0' must be avoided... – Seyi Shoboyejo Mar 03 '21 at 17:53
  • Iterate twice setting all properties to 0 the first time and incrementing the second time. Generally the longer the code the more opportunities for bugs and inefficiencies like these... – Seyi Shoboyejo Mar 03 '21 at 17:57

1 Answers1

0

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"]
Miu
  • 846
  • 8
  • 22