【问题标题】:The most frequent substring of length X长度为 X 的最频繁子串
【发布时间】:2011-05-27 22:24:12
【问题描述】:

我们有一个长度为 N 的字符串和数字 X。

如何在平均O(N)时间内找到长度为N的字符串中出现频率最高的长度为X的子串?

我想,这里有一个类似的问题:https://stackoverflow.com/questions/1597025?tab=votes#tab-top

我想问你如何证明使用的哈希函数的数量只是一个常数。

【问题讨论】:

标签: algorithm substring


【解决方案1】:

suffix tree 应该在 O(n) 时间最坏的情况下给出这个,使用 O(n) 空间。

特别检查上述维基页面的字符串属性子部分下的Functionality部分,其中提到

在 Θ(n) 时间内找到最常出现的最小长度子串。

【讨论】:

    【解决方案2】:

    我建议这种散列函数。让我们假设每个字符串都是 256 基表示法中的数字(而不是我们的 10 基)。因此,对于每个 X 长度的子字符串,我们可以通过这种方式以 10 个基本符号获得它的值:

    #include <iostream>
    #include <string>
    #include <map>
    #include <algorithm>
    
    
    int main()
    {
        std::string s;
        int x;
        std::cin >> s >> x;
    
        unsigned const int base = 256;
        unsigned long long xPowOfBase = 1;
        int i = 0;
        for(i = 1; i <= x; ++i)
            xPowOfBase *= base;
    
        unsigned long long firstXLengthSubString = 0;
        for(i = 0; i < x; ++i)
        {
            firstXLengthSubString *= base;
            firstXLengthSubString += s[i];
        }
    
        unsigned long long nextXLengthSubstring = firstXLengthSubString;
    
        std::map<unsigned long long, std::pair<int, int> > hashTable;
        for(;i <= s.size(); ++i)
        {
            if(hashTable.find(nextXLengthSubstring) != hashTable.end())
                ++hashTable[nextXLengthSubstring].first;
            else
                hashTable.insert(std::make_pair(nextXLengthSubstring, std::make_pair(1, i - x)));
    
            if(i != s.size())
            {
                nextXLengthSubstring *= base;
                nextXLengthSubstring += s[i];
                nextXLengthSubstring -= s[i - x] * xPowOfBase;
            }
        }
    
        std::map<unsigned long long, std::pair<int, int> >::iterator it = hashTable.begin();
        std::map<unsigned long long, std::pair<int, int> >::iterator end_it = hashTable.end();
        std::pair<int, int> maxCountAndFirstPosition = std::make_pair(0, -1);
    
        for(;it != end_it; ++it)
        {
            if(maxCountAndFirstPosition.first < it->second.first)
                maxCountAndFirstPosition = it->second;
        }
    
        std::cout << maxCountAndFirstPosition.first << std::endl;
        std::cout << s.substr(maxCountAndFirstPosition.second, x) << std::endl;
        return 0;
    }
    

    这将适用于 O(n * log(n)) ,使其成为 O(n) 只需使用任何哈希表更改 std::map 。

    【讨论】:

      猜你喜欢
      • 2010-12-08
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-10
      相关资源
      最近更新 更多