Most frequent word in an array of strings - Java Input word array is
{ "geeks", "for", "geeks", "a", "portal", "to", "learn", "can", "be", "computer","science", "zoom", "yup", "fire", "in", "be", "data", "a", "portal","geeks" };

Problem is to find most frequent word in array. 
I want to find solution that can support on adding more element.

I have tried this code :-

package com.techiekunal.examples.datastructure;

import java.util.Iterator;
import java.util.PriorityQueue;

/**
 * MyWord objects will have word and its frequency
 * 
 * @author Kunal.Saxena
 *
 */
class MyWord implements Comparable&lt;MyWord&gt;{

    // word from array
    private String word;

    // word's frequency
    private int count;

    public MyWord(int count, String word) {
        this.count = count;
        this.word = word;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    // Objects are equals if words are same
    @Override
    public boolean equals(Object obj) {
        if(obj == null)
            return false;
        if(this.getClass() != obj.getClass())
            return false;

        MyWord myWord = (MyWord) obj;
        return this.word.equals(myWord.word);
    }

    @Override
    public int hashCode() {
        return super.hashCode();
    }

    // Printing word and count against it
    @Override
    public String toString() {
        return this.word + " : " + this.count;
    }

    // comparison for descending order of count
    @Override
    public int compareTo(MyWord o) {
        if(this.count &gt; o.count) {
            return -1;
        }
        if(this.count &lt; o.count) {
            return 1;
        }
        return 0;
    }

}

public class MostFrequentUsedWords {

    // Input array
    private static String[] arr = { "geeks", "for", "geeks", "a", "portal", "to", "learn", "can", "be", "computer",
            "science", "zoom", "yup", "fire", "in", "be", "data", "a", "portal","geeks" };

    // Queue will work as max heap to store words
    private static PriorityQueue&lt;MyWord&gt; queue = new PriorityQueue&lt;&gt;();

    // Creating PriorityQueue from given input array
    private static void createQueue() {

        for (String word : arr) {
            // check if word already exists
            if (queue.contains(new MyWord(1, word))) {

                MyWord oldWord = null;
                // iterate to find word : we need latest frequency of that word
                Iterator&lt;MyWord&gt; itr = queue.iterator();
                while (itr.hasNext()) {

                    MyWord next = itr.next();
                    if (next.getWord().equals(word)) {
                        oldWord = next;
                    }
                }
                // create new word by incrementing frequency, remove old word from queue, adding new word to queue
                MyWord newWord = new MyWord(oldWord.getCount() + 1, oldWord.getWord());
                queue.remove(oldWord);
                queue.add(newWord);

            } else {
                // if word is not in queue : add it with frequency 1
                MyWord newWord = new MyWord(1, word);
                queue.add(newWord);
            }
        }

    }

    public static void main(String[] args) {

        // Create priority queue
        createQueue();

        // Print Queue
        while (!queue.isEmpty()) {
            System.out.println(queue.poll());
        }
    }

}


My output is :-


geeks : 3
a : 2
portal : 2
be : 2
yup : 1
zoom : 1
science : 1
computer : 1
in : 1
can : 1
learn : 1
to : 1
data : 1
fire : 1
for : 1




I implemented this using priority queue and it is working fine. it is like creating max heap. But its complexity is n^2. Need help if this can be solve in less complex way.
As you noticed, searching for your entries is adding to your time complexity, because you have to run down your queue. Priority queues are very good at polling the top element, but not optimized for searching for specific entries.

You can optimize for searching by using a Map&lt;String, Integer&gt; for counting frequency, and then use a NavigableMap&lt;Integer, Set&lt;String&gt;&gt; for maintaining order (1). Adding an entry will look like this:

NavigableMap&lt;Integer, Set&lt;String&gt;&gt; ordered;
Map&lt;String, Integer&gt; frequency;

void add(String word) {
  int count = frequency.getOrDefault(word, 0);
  if ( count &gt; 0 ) {
    ordered.get(count).remove(word);
  }
  ordered.computeIfAbsent(count + 1, HashSet::new).add(word);
  frequency.put(word, count + 1);
}


(1) If you're confident about your data being densely distributed and bounded, you can replace this with an array for quicker access—approaching O(1) i.o. O(log N)—but it's going to make your code messier dealing with edge cases.



I do have two recommendations for your code.

When searching for an element in the queue, you can abort once it's found. On average, this will halve your time spent searching:

Iterator&lt;MyWord&gt; itr = queue.iterator();
while (itr.hasNext()) {
   MyWord next = itr.next();
   if (next.getWord().equals(word)) {
       oldWord = next;
       break;  // &lt;-- found, abort search
   }
}


And a nitpick from an 'elegance' point of view: consider adding a method to MyWord that creates a new, incremented instance. Right now, outside code is accessing the fields and creating new instances with it. This is something MyWord can handle internally.

public MyWord incremented() {
    return new MyWord(count + 1, word);
}