有一连串的词汇,非常大。随着单词不断出现,可以要求它判断已经看到的流中是否发生了短语? 在不同的时间可能会有多个此类查询。
例如,假设到目前为止看到的单词流是:
你好世界是另一个程序员
然后,要求判断是否已经看到短语here is another
,在这种情况下是正确的。
如何以最佳方式退回?
我一直在尝试使用图形构建解决方案并在查询时执行BFS,但它会带来两个问题:
首先,为了达到最佳效果,我还必须存储 words =>哈希表中图对中节点的地址。
其次,当存在周期时,算法会在流中失败:a b c d a b c e
建议满足要求的最佳解决方案。
答案 0 :(得分:1)
您可以查找“后缀树的在线构建”并找到Ukkonen处理流的算法,并在处理完每个字符后为您的流准备一个后缀树,并且运行时间和空间为O(n )如果到目前为止你已经看过n个字符。然后,每次给出一个查询短语时,您可以使用子串匹配算法为后缀树查找给定查询短语的所有匹配项,如果查询短语具有长度,查询时间最佳为O(m)以查找匹配项米。
答案 1 :(得分:1)
因为您正在接收要以流方式搜索的文本正文,所以“预处理”文本以进行更有效的搜索是没有意义的。这是C#中一个有效的实现,它以流方式处理要搜索的文本。
static IEnumerable<int> Search(string text, string query)
{
var D = new Dictionary<int, int>();
//Loop invariant: D[i] == j iff text[i..(i+j)] == query[0..j]
// for all pairs (i,j) in D
for (int i = 0; i < text.Length; i++)
{
foreach (var k in D.Keys.ToList())
{
D[k] = D[k] + 1;
if (D[k] == query.Length)
{
yield return k;
D.Remove(k);
}
else if (text[i] != query[D[k]])
{
D.Remove(k);
}
}
if (text[i] == query[0])
D.Add(i, 0);
}
foreach (var k in D.Keys)
{
if (D[k] == query.Length)
yield return k;
}
}
基于流的版本可以如下实现。我认为流末端的情况可能无法正确处理,但你应该能够将这个想法调整为适用于那种边缘情况的东西。
class SearcherState
{
public Dictionary<int, int> D = new Dictionary<int, int>();
public int i = 0;
}
static Func<char, int?> Searcher(string query)
{
var state = new SearcherState();
return c =>
{
int? result = null;
foreach (var k in state.D.Keys.ToList())
{
state.D[k] = state.D[k] + 1;
if (state.D[k] == query.Length)
{
result = k;
state.D.Remove(k);
}
else if (c != query[state.D[k]])
{
state.D.Remove(k);
}
}
if (c == query[0])
state.D.Add(state.i, 0);
state.i++;
return result;
};
}