Постановка на проблема:

Двигател за броене на думи

Приложете функция за сканиране на документи wordCountEngine, която получава низ document и връща списък с всички уникални думи в него и техния брой срещания, сортирани по броя на срещанията в низходящ ред. Ако две или повече думи имат еднакъв брой, те трябва да бъдат сортирани според реда им в оригиналното изречение. Да приемем, че всички букви са в английската азбука. Вашата функция трябва да е нечувствителна към главни и малки букви, така че например думите “Perfect” и “perfect” трябва да се считат за една и съща дума.

Машината трябва да премахне пунктуацията (дори в средата на думата) и да използва бели интервали за разделяне на думите.

Анализирайте времевата и пространствената сложност на вашето решение. Опитайте се да оптимизирате за времето, като запазите сложността на полиномното пространство.

Примери:

input:  document = "Practice makes perfect. you'll only
                    get Perfect by practice. just practice!"
output: [ ["practice", "3"], ["perfect", "2"],
          ["makes", "1"], ["youll", "1"], ["only", "1"], 
          ["get", "1"], ["by", "1"], ["just", "1"] ]

Решение:

public class WordCountEngine {
    public static void main(String[] args) {
        String document = "Practice makes perfect. you'll only get Perfect by practice. just practice !";

        String[][] output=wordCountEngine(document);

        Arrays.stream(output).forEach(arr->{
            System.out.println(arr[0]+"->"+arr[1]);
        });

    }

    static String[][] wordCountEngine(String doc) {
        String[] allWords = doc.toLowerCase().split("[^a-zA-Z']+");
        LinkedHashMap<String, Integer> counter = new LinkedHashMap<>();

        Arrays.stream(allWords).forEach(w -> {
            counter.compute(w, (key, value) -> value == null ? 1 : value + 1);
        });
        System.out.println(counter);


        TreeMap<Integer, HashSet<String>> sortedMap = new TreeMap<>(Collections.reverseOrder());
        Arrays.stream(allWords).forEach(w -> {
            int i = counter.get(w);
            if (sortedMap.containsKey(i)) {
                HashSet<String> set = sortedMap.get(i);
                set.add(w);
                sortedMap.put(i, set);
            } else {
                HashSet<String> hashSet = new HashSet<>();
                hashSet.add(w);
                sortedMap.put(i, hashSet);
            }

        });

        System.out.println(sortedMap);
        String[][] result=new String[counter.size()][2];
        int iterator=0;
        for(Map.Entry<Integer,HashSet<String>> entry:sortedMap.entrySet()){
            int count=entry.getKey();

            for(Map.Entry<String,Integer> e:counter.entrySet()){
                if(e.getValue()==count){
                    String[] res=new String[2];
                    res[0]=e.getKey();
                    res[1]=String.valueOf(count);
                    result[iterator]=res;
                    iterator++;
                }

            }
        }

        return result;
    }
}