Durante uma entrevista para uma posição de desenvolvedor Java, me perguntaram o seguinte:
Escreva uma função que use dois parâmetros:
- uma String representando um documento de texto e
- um número inteiro fornecendo o número de itens a serem retornados.
Implemente a função para que ela retorne uma lista de Strings ordenadas por frequência de palavra, a palavra que ocorre com mais frequência primeiro. Sua solução deve ser executada em tempo em que é o número de caracteres no documento.
A seguir é o que eu respondi (em pseudocódigo), não é mas sim O ( n log n ) tempo por causa da classificação. Não consigo descobrir como fazê-lo O ( n ) tempo.
wordFrequencyMap = new HashMap<String, Integer>();
words = inputString.split(' ');
for (String word : words) {
count = wordFrequencyMap.get(word);
count = (count == null) ? 1 : ++count;
wordFrequencyMap.put(word, count);
}
return wordFrequencyMap.sortByValue.keys
Alguém sabe ou pode me dar algumas dicas?
algorithms
sorting
strings
data-mining
user2712937
fonte
fonte
Hashtable
não é relevante para este site (mas você pode perguntar sobre isso no StackOverflow) e, da mesma forma, se é Java legado ou não, é realmente irrelevante para os propósitos deste site.Respostas:
Sugiro uma variação da contagem de distribuição:
maxWordCound
. -maxWordCount
. Tipo de entrada são listas de strings. - , já que a contagem não pode ser maior.Provavelmente, você pode substituir o teste por outras estruturas de dados na primeira fase.
fonte
A coleta de contagens de ocorrências é O (n), portanto, o truque é realmente encontrar apenas as contagens de k principais ocorrências.
Um heap é uma maneira comum de agregar os principais valores de k, embora outros métodos possam ser usados (consulte https://en.wikipedia.org/wiki/Partial_sorting ).
Assumindo que k é o segundo parâmetro acima e que é uma constante na declaração do problema (parece ser):
Como o tamanho do heap é uma constante, as operações do heap são O (1), portanto, a etapa 3 é O (n).
O heap também pode ser mantido dinamicamente ao criar o trie.
fonte
Seu algoritmo nem roda no tempo ; inserir Θ ( n ) coisas em um hashtable custa tempo Ω ( n 2 ) já (na pior das hipóteses).O(nlogn) Θ(n) Ω(n2)
O que se segue está errado ; Estou deixando aqui por enquanto para fins ilustrativos.
O algoritmo a seguir é executado no pior dos casos (assumindo um alfabeto Σ de tamanho constante), n o número de caracteres no texto.O(n) Σ n
Construa uma árvore de sufixos do texto, por exemplo, com o algoritmo de Ukkonen .
Se a construção ainda não fizer isso, adicione o número de folhas alcançáveis em cada nó (interno).
Atravesse a árvore da raiz e corte todos os galhos no primeiro espaço (branco).
Atravesse a árvore e classifique a lista de filhos de cada nó pela contagem de folhas.
O rendimento da árvore (folhas da esquerda para a direita) agora é uma lista de todas as palavras, classificadas por frequência.
Em relação ao tempo de execução:
Limites mais precisos podem ser obtidos parametrizando o tempo de execução com o número de palavras diferentes; se houver poucos, a árvore será pequena após 2.
fonte
HashMap
Ou, se você quiser jogar um pouco mais seguro, antes de dar uma resposta, primeiro pergunte "você se importa com a diferença entre esperadoO(n) running time and worst-case O(n) running time?". Then tailor your answer accordingly. Be prepared for the interviewer to ask you how you would choose, in practice. (If so, score! That's a question you should be able to hit out of the ballpark.)
fonte
Hashtable based solution
Not sure why hashtable makes the complexityΩ(n2) if n is the number of characters (not words).
If you iterate through every character in the document and as you are iterating, calculate the hashcode of the word, you will have gone throughn characters. That is, as soon as a letter is encountered, the word begins, so start computing hash until the word ends (there are some special cases for punctuation but those do not affect the complexity). For every word, once the hash is computed, add it to a hashtable. This is to avoid going over every word twice, i.e. first to iterate through the document to find the words and then to insert them in a hashtable, although the complexity in that case could also be Ω(n) .
Collisions in the hashtable are surely a problem, and depending on how big the original hashtable was and how good the hashing algorithm is, one could approach close toO(1) for insertions and keeping counts and thus O(n) for the algorithm, although at the expense of memory. However, I still cannot appreciate how the worst case can be asserted to be O(n2) if n is the number of characters.
The assumption is that the hashing algorithm is linear in time in relation to the number of characters.
Radix sort based solution
Alternatively, assuming English, since the length of the words is well-known, I would instead create a grid and apply radix sort which isO(kN) where k would be the maximum length of a word in the English language, and N is the total number of words. Given n is the number of characters in the document, and k is a constant, asymptotically this amounts O(n) .
Now count the frequency of each word. Since the words are sorted, we will be comparing each word to its preceding word to see if it's the same one or different. If it's the same, we remove the word and add a count to the previous. If different, just make the count 1 and move on. This requires2n comparisons where n is the number of characters, and thus O(n) in complexity as a whole.
The top few longest words in English are ridiculously long, but then one could cap the word length at a reasonable number (such as 30 or smaller) and truncate words accepting the margin of error that might come with it.
fonte