Dane wejściowe: dodatnia liczba całkowita K i duży tekst. Tekst można w rzeczywistości postrzegać jako ciąg słów. Więc nie musimy się martwić, jak podzielić to na ciąg słów.
Wynik: Najczęstsze K słów w tekście.
Moje myślenie jest takie.
użyj tablicy Hash, aby zapisać częstotliwość wszystkich słów podczas przechodzenia przez całą sekwencję słów. W tej fazie kluczem jest „słowo”, a wartością jest „częstotliwość słów”. To zajmuje O (n) czasu.
sortować parę (słowo, częstotliwość słów); a kluczem jest „częstotliwość słów”. To zajmuje O (n * lg (n)) czasu przy normalnym algorytmie sortowania.
Po sortowaniu bierzemy tylko pierwsze K słów. To zajmuje O (K) czasu.
Podsumowując, całkowity czas wynosi O (n + n lg (n) + K) , Ponieważ K jest na pewno mniejsze od N, więc w rzeczywistości wynosi O (n lg (n)).
Możemy to poprawić. Właściwie chcemy tylko najlepszych słów K. Innymi słowy, częstotliwość nie dotyczy nas. Możemy więc użyć „częściowego sortowania sterty”. W kroku 2) i 3) nie zajmujemy się tylko sortowaniem. Zamiast tego zmieniamy go na
2 ') zbuduj stos par (słowo, częstotliwość słowa) z kluczem „częstotliwość słowa”. Zbudowanie sterty zajmuje O (n) czasu;
3 ') wyodrębnij górne K słów ze stosu. Każda ekstrakcja to O (lg (n)). Zatem całkowity czas wynosi O (k * lg (n)).
Podsumowując, to rozwiązanie kosztuje czas O (n + k * lg (n)).
To tylko moja myśl. Nie znalazłem sposobu na ulepszenie kroku 1).
Mam nadzieję, że niektórzy eksperci ds. Wyszukiwania informacji mogą rzucić więcej światła na to pytanie.
źródło
Odpowiedzi:
Można to zrobić w czasie O (n)
Rozwiązanie 1:
Kroki:
Policz słowa i zhaszuj, co trafi do takiej struktury
Przejdź przez hash i znajdź najczęściej używane słowo (w tym przypadku „foo” 100), a następnie utwórz tablicę o tym rozmiarze
Następnie możemy ponownie przejść przez hash i użyć liczby wystąpień słów jako indeksu tablicy, jeśli nie ma nic w indeksie, utworzyć tablicę, w przeciwnym razie dołącz ją do tablicy. Następnie otrzymujemy tablicę taką jak:
Następnie po prostu przejdź przez tablicę od końca i zbierz k słów.
Rozwiązanie 2:
Kroki:
źródło
Nie uzyskasz ogólnie lepszego czasu działania niż rozwiązanie, które opisałeś. Musisz wykonać co najmniej O (n) pracę, aby ocenić wszystkie słowa, a następnie O (k) dodatkową pracę, aby znaleźć k najlepszych terminów.
Jeśli zestaw problemów jest naprawdę duży, możesz użyć rozwiązania rozproszonego, takiego jak mapowanie / redukcja. Niech n robotników mapy policzy częstotliwości na 1 / n-tej części tekstu i dla każdego słowa wyślij je do jednego z m pracowników redukujących obliczonych na podstawie skrótu słowa. Następnie reduktory sumują liczby. Sortuj według wyników reduktorów daje najpopularniejsze słowa w kolejności popularności.
źródło
Mała wariacja na temat twojego rozwiązania daje algorytm O (n) , jeśli nie zależy nam na uszeregowaniu najwyższego K, i rozwiązanie O (n + k * lg (k)) , jeśli to zrobimy. Uważam, że obie te granice są optymalne w ramach stałego czynnika.
Optymalizacja pojawia się ponownie po przejrzeniu listy i wstawieniu do tablicy skrótów. Możemy użyć algorytmu mediany median , aby wybrać K-ty największy element na liście. Ten algorytm jest możliwy do udowodnienia O (n).
Po wybraniu najmniejszego elementu Kth dzielimy listę wokół tego elementu, tak jak w quicksort. Jest to oczywiście również O (n). Wszystko po „lewej” stronie osi znajduje się w naszej grupie elementów K, więc gotowe (możemy po prostu wyrzucić wszystko inne w trakcie).
Więc ta strategia jest taka:
Jeśli chcesz uszeregować K elementów, po prostu posortuj je za pomocą dowolnego wydajnego sortowania porównawczego w czasie O (k * lg (k)), uzyskując całkowity czas wykonania O (n + k * lg (k)).
Ograniczenie czasu O (n) jest optymalne w ramach stałego czynnika, ponieważ musimy zbadać każde słowo przynajmniej raz.
Ograniczenie czasu O (n + k * lg (k)) jest również optymalne, ponieważ nie ma opartego na porównaniu sposobu sortowania k elementów w czasie krótszym niż k * lg (k).
źródło
Jeśli Twoja „duża lista słów” jest wystarczająco duża, możesz po prostu pobrać próbkę i uzyskać szacunki. W przeciwnym razie lubię agregację skrótów.
Edycja :
Przez próbkę mam na myśli wybranie podzbioru stron i obliczenie najczęściej występującego słowa na tych stronach. Zakładając, że wybrałeś strony w rozsądny sposób i wybrałeś statystycznie istotną próbkę, twoje szacunki dotyczące najczęściej występujących słów powinny być rozsądne.
Takie podejście jest naprawdę rozsądne tylko wtedy, gdy masz tak dużo danych, że ich przetwarzanie jest po prostu głupie. Jeśli masz tylko kilka megabajtów, powinieneś być w stanie przedrzeć się przez dane i obliczyć dokładną odpowiedź bez wysiłku, zamiast zawracać sobie głowę obliczeniem oszacowania.
źródło
Możesz skrócić czas dalej, dzieląc na partycje za pomocą pierwszej litery słów, a następnie dzieląc największy zestaw wielowyrazowy za pomocą następnego znaku, aż uzyskasz k zestawów pojedynczych słów. Użyłbyś pewnego rodzaju drzewa 256-ścieżkowego z listami częściowych / pełnych słów na liście. Musiałbyś być bardzo ostrożny, aby nie powodować wszędzie kopii łańcuchowych.
Ten algorytm to O (m), gdzie m to liczba znaków. Pozwala to uniknąć zależności od k, co jest bardzo miłe dla dużego k [przy okazji, twój opublikowany czas działania jest nieprawidłowy, powinien wynosić O (n * lg (k)) i nie jestem pewien, co to jest m].
Jeśli uruchomisz oba algorytmy obok siebie, uzyskasz coś, co na pewno jest asymptotycznie optymalnym algorytmem O (min (m, n * lg (k))), ale mój powinien być średnio szybszy, ponieważ nie obejmuje haszowanie lub sortowanie.
źródło
Masz błąd w opisie: liczenie zajmuje O (n) czasu, ale sortowanie zajmuje O (m * lg (m)), gdzie m to liczba unikalnych słów. Zwykle jest to znacznie mniej niż całkowita liczba słów, więc prawdopodobnie powinno po prostu zoptymalizować sposób budowania skrótu.
źródło
Twój problem jest taki sam jak ten - http://www.geeksforgeeks.org/find-the-k-most-frequent-words-from-a-file/
Użyj Trie i min heap, aby skutecznie go rozwiązać.
źródło
Jeśli szukasz listy k najczęściej występujących słów w tekście dla dowolnego praktycznego k i dowolnego języka naturalnego, to złożoność algorytmu nie ma znaczenia.
Wystarczy pobrać , powiedzmy, kilka milionów słów ze swojego tekstu, przetworzyć to za pomocą dowolnego algorytmu w ciągu kilku sekund , a najczęstsze zliczenia będą bardzo dokładne.
Na marginesie, złożoność algorytmu pozorowanego (1. policz wszystkie 2. posortuj liczby 3. wybierz najlepszą) to O (n + m * log (m)), gdzie m to liczba różnych słów w twoim tekst. log (m) jest znacznie mniejszy niż (n / m), więc pozostaje O (n).
Praktycznie liczy się długi krok.
źródło
Oto kod
}
Oto testy jednostkowe
Aby uzyskać więcej informacji, zapoznaj się z tym przypadkiem testowym
źródło
użyj tablicy Hash, aby zapisać częstotliwość wszystkich słów podczas przechodzenia przez całą sekwencję słów. W tej fazie kluczem jest „słowo”, a wartością jest „częstotliwość słów”. Zajmuje to O (n) czasu, tak samo jak w przypadku każdego wyjaśnionego powyżej
Podczas wstawiania samego w hashmap, zachowaj zestaw drzew (specyficzny dla java, są implementacje w każdym języku) o rozmiarze 10 (k = 10), aby zachować 10 najczęściej występujących słów. Do rozmiaru mniej niż 10, dodawaj go dalej. Jeśli rozmiar jest równy 10, jeśli wstawiony element jest większy niż element minimalny, czyli pierwszy element. Jeśli tak, usuń go i włóż nowy element
Aby ograniczyć rozmiar zbioru drzew, zobacz ten link
źródło
Załóżmy, że mamy sekwencję słów „reklama” „reklama” „chłopiec” „duży” „zły” „com” „przyjdź” „zimno”. A K = 2. jak wspomniałeś o „partycjonowaniu przy użyciu pierwszej litery słów”, otrzymaliśmy („reklama”, „reklama”) („chłopiec”, „duży”, „zły”) („com” „przyjdź” „zimno”) ” podzielenie największego zestawu wielowyrazowego przy użyciu następnego znaku aż do uzyskania k zestawów pojedynczych słów. " podzieli („chłopak”, „duży”, „zły”) („com” „przyjdzie” „zimno”), pierwsza partycja („reklama”, „reklama”) zostanie pominięta, podczas gdy „reklama” to w rzeczywistości najczęściej używane słowo.
Być może źle zrozumiałem twój punkt widzenia. Czy możesz szczegółowo opisać proces dotyczący partycji?
źródło
Uważam, że ten problem można rozwiązać za pomocą algorytmu O (n). Moglibyśmy przeprowadzić sortowanie w locie. Innymi słowy, sortowanie w tym przypadku jest podproblem tradycyjnego problemu sortowania, ponieważ tylko jeden licznik jest zwiększany o jeden za każdym razem, gdy uzyskujemy dostęp do tablicy skrótów. Początkowo lista jest posortowana, ponieważ wszystkie liczniki są zerowe. Ponieważ zwiększamy liczniki w tabeli skrótów, księgujemy kolejną tablicę wartości skrótu uporządkowanych według częstotliwości w następujący sposób. Za każdym razem, gdy zwiększamy licznik, sprawdzamy jego indeks w tablicy rankingowej i sprawdzamy, czy jego liczba przekracza jego poprzednik na liście. Jeśli tak, zamieniamy te dwa elementy. W związku z tym otrzymujemy rozwiązanie, które jest najwyżej O (n), gdzie n jest liczbą słów w tekście oryginalnym.
źródło
Ja też z tym walczyłem i zainspirował mnie @aly. Zamiast sortować później, możemy po prostu zachować wstępnie posortowaną listę słów (
List<Set<String>>
), a słowo będzie w zestawie na pozycji X, gdzie X jest bieżącą liczbą słów. Ogólnie rzecz biorąc, tak to działa:Map<String, Integer>
.Wadą tego jest to, że lista może być duża - można ją zoptymalizować za pomocą
TreeMap<Integer, Set<String>>
- ale to doda trochę narzutu. Ostatecznie możemy użyć mieszanki HashMap lub naszej własnej struktury danych.Kod
źródło
Po prostu znajduję inne rozwiązanie tego problemu. Ale nie jestem pewien, czy to prawda. Rozwiązanie:
źródło
Spróbuj pomyśleć o specjalnej strukturze danych, aby podejść do tego rodzaju problemów. W tym przypadku specjalny rodzaj drzewa, taki jak próba przechowywania łańcuchów w określony sposób, jest bardzo wydajny. Lub drugi sposób na zbudowanie własnego rozwiązania, takiego jak liczenie słów. Wydaje mi się, że ten TB danych byłby w języku angielskim, wtedy mamy ogólnie około 600 000 słów, więc będzie można zapisać tylko te słowa i policzyć, które ciągi będą się powtarzać + to rozwiązanie będzie wymagało wyrażenia regularnego, aby wyeliminować niektóre znaki specjalne. Jestem pewien, że pierwsze rozwiązanie będzie szybsze.
http://en.wikipedia.org/wiki/Trie
źródło
To ciekawy pomysł do przeszukania i mógłbym znaleźć ten artykuł związany z Top-K https://icmi.cs.ucsb.edu/research/tech_reports/reports/2005-23.pd f
Ponadto istnieje implementacja nim tutaj .
źródło
Najprostszy kod, aby uzyskać występowanie najczęściej używanego słowa.
źródło
W takich sytuacjach zalecam korzystanie z wbudowanych funkcji Java. Ponieważ są już dobrze przetestowane i stabilne. W tym zadaniu powtórzenia słów znajduję za pomocą struktury danych HashMap. Następnie przekazuję wyniki do tablicy obiektów. Sortuję obiekt według Arrays.sort () i wypisuję k górnych słów i ich powtórzeń.
Więcej informacji można znaleźć pod adresem https://github.com/m-vahidalizadeh/foundations/blob/master/src/algorithms/TopKWordsTextFile.java . Mam nadzieję, że to pomoże.
źródło
I recommend to use Java built-in features
Jak przetwarzanie wszystkich pętli i strumieni ?)**
};
źródło