如何最佳地返回短语是否出现在单词流中?

时间:2013-07-14 18:20:14

标签: algorithm data-structures stream

有一连串的词汇,非常大。随着单词不断出现,可以要求它判断已经看到的流中是否发生了短语在不同的时间可能会有多个此类查询。

例如,假设到目前为止看到的单词流是:

  

你好世界是另一个程序员

然后,要求判断是否已经看到短语here is another,在这种情况下是正确的。

如何以最佳方式退回?

我一直在尝试使用图形构建解决方案并在查询时执行BFS,但它会带来两个问题:

  • 首先,为了达到最佳效果,我还必须存储 words =>哈希表中图对中节点的地址。

  • 其次,当存在周期时,算法会在流中失败:a b c d a b c e

建议满足要求的最佳解决方案。

2 个答案:

答案 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;
    };
}