如何设计一种算法,可以在 O(n) 时间内返回文档中最常用的 10 个单词?如果可以使用额外的空间。
我可以使用 count 解析单词并将其放置在哈希图中。但接下来我必须对值进行排序以获得最常见的值。此外,我必须有一个映射 btw 值 -> 键,因为值可能重复,所以无法维护。
那么我该如何解决呢?
如何设计一种算法,可以在 O(n) 时间内返回文档中最常用的 10 个单词?如果可以使用额外的空间。
我可以使用 count 解析单词并将其放置在哈希图中。但接下来我必须对值进行排序以获得最常见的值。此外,我必须有一个映射 btw 值 -> 键,因为值可能重复,所以无法维护。
那么我该如何解决呢?
这是一个简单的算法:
O(n)运行时间。
哈希表 + 数组的O(n)存储
(旁注:您可以将 HashTable 视为字典:一种存储键值对的方法,其中键是唯一的。从技术上讲,HashMap 意味着异步访问,而 HashTable 意味着同步。)
如果您使用正确的数据结构,它可以在 O(n) 中完成。
考虑 a Node
,由两件事组成:
Node
。所有指针最初都设置为NULL
.创建一个根节点。定义一个“当前”Node
指针,最初将其设置为根节点。然后遍历文档的所有字符并执行以下操作:
NULL
- 分配它。当前Node
指针被更新。Node
。然后重置“当前”Node
指针以指向根节点。通过这样,您可以在 O(n) 中构建一棵树。每个元素(节点和离开)都表示一个特定的单词,以及它的计数器。
然后遍历树以找到具有最大计数器的节点。它也是 O(n),因为树中的元素数量不大于 O(n)。
更新:
最后一步不是强制性的。实际上,最常用的词可能会在字符处理过程中被更新。下面是一个伪代码:
struct Node
{
size_t m_Counter;
Node* m_ppNext[255];
Node* m_pPrev;
Node(Node* pPrev) :m_Counter(0)
{
m_pPrev = pPrev;
memset(m_ppNext, 0, sizeof(m_ppNext));
}
~Node()
{
for (int i = 0; i < _countof(m_ppNext) i++)
if (m_ppNext[i])
delete m_ppNext[i];
}
};
Node root(NULL);
Node* pPos = &root;
Node* pBest = &root;
char c;
while (0 != (c = GetNextDocumentCharacter()))
{
if (c == ' ')
{
if (pPos != &root)
{
pPos->m_Counter++;
if (pBest->m_Counter < pPos->m_Counter)
pBest = pPos;
pPos = &root;
}
} else
{
Node*& pNext = pPos->m_ppNext[c - 1];
if (!pNext)
pNext = new Node(pPos);
pPos = pNext;
}
}
// pBest points to the most common word. Using pBest->m_pPrev we iterate in reverse order through its characters
最快的方法是使用基数树。您可以将单词数存储在基数树的叶子上。保留一个单独的 10 个最常用词及其出现次数的列表,以及一个存储进入该列表所需的阈值的变量。将项目添加到树中时更新此列表。
维护 (word,count) 的映射将是 O(n)。
构建地图后,遍历键并检索十个最常用的键。
O(n) + O(n)
-- 但对这个解决方案并不完全满意,因为需要额外的外部内存。
我会使用 ArrayList 和 HashTable。
这是我正在考虑的算法,
Loop through all the word in the document.
if (HashTable.contains(word) )
increment count for that word in the HashTable;
else
ArrayList.add(word);
HashTable.add(word);
word count in HashTable = 1;
遍历整个文档后,
Loop through ArrayList<word>
Retrieve the word count for that word from the HashTable;
Keep a list of the top 10 words;
构建 HashTable 和 ArrayList 的运行时间应该是 O(n)。制作前 10 个列表应该是 O(m),其中 m 是唯一单词的数量。O(n+m) 其中 n>>m --> O(n)