今天我参加了一家公司的笔试。整体测试侧重于数据结构。我遇到了一个我认为已经解决的问题。但我在计算数据结构的Big O函数时遇到了困难。我将提出我提出的问题和答案。
给定您需要存储的文档和文档中的单词,并且应该能够在输入任何单词时返回计数。您获得了
char* GetNextWord()
。
- 您将选择哪种数据结构
- 提供算法
- 算法的顺序是什么
醇>
对于问题1,我写了我会去TRIE数据结构。对于问题2,我给出了一个简短的算法。我写道,我将构建TRIE数据结构如下。
struct TRIE{
boolean isWord;
int count;
Node* myList;
}
struct Node{
char* character;
Node *next;
TRIE *child;
}
我有方法constructTrie()
,它会为每个单词执行addToTrie()
。
我写的addToTrie()
的顺序是O( k ),其中 k 是长度。 constructTrie()
的顺序为 N * O( k ),其中 N 将是单词的数量。
现在我的问题是: 我提到的订单是否正确?如果没有,如何在将来攻击这样的问题(假设ds找到订单)。使用O( k )后我感到很困惑。这让我假设O(1)。
提示/提示/建议是开放的!
修改:更正了问题,明确提到应为所有唯一字词存储字数。
答案 0 :(得分:2)
比较两个通用字符串取Θ(k)(k = min strlen),并且字数是N,你必须查看,所以Ω(Nk)应该是你能得到的最有效的复杂性。
答案 1 :(得分:1)
如果你真的想使用特里,那么addToTrie()
确实会 O(k),其中k是你要添加的单词的长度。 constructTrie()
将采用 O(Nk),其中 N 是单词的数量,如果您只是为每个单词调用addToTrie()
。但是,您无需为每个单词调用addToTrie()
函数。完成添加单词后,只需将trie指针重置为trie的根,然后在移动当前单词时移动指针,随着时间的推移添加字符。伪代码:
trieNode *curr = trieRoot;
for each character c in document
if it's a word terminator (space etc)
add a character at curr signaling the end of the current word ('\0' maybe);
curr = trieRoot;
else if character is not a separator
add character c at curr->next->character[c];
curr = curr->next;
这将为您提供构建特里结构的 O(C)运行时间,其中<strong> C 是文档中的字符数。
现在,这引出了一个问题:为什么你需要特里?显然你想出了一种方法来检测一个单词何时结束,那么为什么必须将你的单词添加到一个单词?这太过分了。您需要的唯一数据结构是一些变量:一个用于跟踪当前字符,一个用于跟踪前一个字符,另一个用于计算单词。这很容易在 O(C)中完成,如下所示:
char prev = '\0';
char curr;
int count = 0;
for each character curr
if curr is a word separator and prev isn't
++count;
prev = curr;
我认为使用trie来解决这个问题是没有意义的,这只会使事情复杂化。我想如果他们想测试你对尝试的了解,那么他们就会给你一个问题,让你更有意义。
即使他们给你一个getNextWord()
功能(你有没有使用它?因为没有它你可以做得更好),我猜它会在没有更多单词的情况下返回“\ 0”或其他东西?那么为什么你不能直接调用它直到它返回“\ 0”并计算这样的单词?无论哪种方式,特里在这里都没有意义。