Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 在给定源字符串中查找给定字符串的所有字符串置换_String_Algorithm_Hashmap - Fatal编程技术网

String 在给定源字符串中查找给定字符串的所有字符串置换

String 在给定源字符串中查找给定字符串的所有字符串置换,string,algorithm,hashmap,String,Algorithm,Hashmap,我们得到了一个模式字符串:“foo”和一个源字符串:“foobaroofzaqofom”,我们需要找到所有出现在任何字母顺序中的单词模式字符串。因此,对于给定的示例,解决方案看起来像:['foo','oof','ofo'] 我有一个解决方案,但我不确定它是否是最有效的: 创建模式字符串字符的哈希映射,其中每个字符是一个键,每个值是模式中字符的计数器。对于给定的示例,它将是{{f:1},{o:2} 查看源字符串,如果从hash_映射中找到一个元素,则尝试查找模式的所有其余元素 如果所有元素都找到了

我们得到了一个模式字符串:“foo”和一个源字符串:“foobaroofzaqofom”,我们需要找到所有出现在任何字母顺序中的单词模式字符串。因此,对于给定的示例,解决方案看起来像:['foo','oof','ofo']

我有一个解决方案,但我不确定它是否是最有效的:

  • 创建模式字符串字符的哈希映射,其中每个字符是一个键,每个值是模式中字符的计数器。对于给定的示例,它将是{{f:1},{o:2}
  • 查看源字符串,如果从hash_映射中找到一个元素,则尝试查找模式的所有其余元素
  • 如果所有元素都找到了,那么这就是我们的解决方案,如果不能继续下去的话
  • 下面是c++中的一个实现:

    set<string> FindSubstringPermutations(string& s, string& p)
    {
        set<string> result; 
        unordered_map<char, int> um;
    
        for (auto ch : p)
        {
            auto it = um.find(ch);
            if (it == um.end())
                um.insert({ ch, 1 });
            else
                um[ch] += 1;
        }
    
        for (int i = 0; i < (s.size() - p.size() + 1); ++i)
        {
            auto it = um.find(s[i]);
            if (it != um.end())
            {
                decltype (um) um_c = um;
                um_c[s[i]] -= 1;
                for (int t = (i + 1); t < i + p.size(); ++t)
                {
                    auto it = um_c.find(s[t]);
                    if (it == um_c.end())
                        break;
                    else if (it->second == 0)
                        break;
                    else
                        it->second -= 1;
                }
    
                int sum = 0;
                for (auto c : um_c)
                    sum += c.second;
    
                if (sum == 0)
                    result.insert(s.substr(i, p.size()));
            }
        }
    
        return result;
    }
    
    set FindSubstringPermutations(字符串&s,字符串&p)
    {
    设定结果;
    无序地图;
    用于(自动通道:p)
    {
    自动it=um.find(ch);
    if(it==um.end())
    插入({ch,1});
    其他的
    um[ch]+=1;
    }
    对于(int i=0;i<(s.size()-p.size()+1);+i)
    {
    自动it=um.find(s[i]);
    如果(it!=um.end())
    {
    decltype(um)um_c=um;
    um_c[s[i]-=1;
    对于(int t=(i+1);tsecond==0)
    打破
    其他的
    它->秒-=1;
    }
    整数和=0;
    用于(自动c:um_c)
    总和+=c秒;
    如果(总和=0)
    结果.插入(s.substr(i,p.size());
    }
    }
    返回结果;
    }
    
    复杂性接近O(n),我不知道如何更精确地计算


    所以问题是:有没有有效的解决方案,因为使用hash_-map有点麻烦,我认为可能有更有效的解决方案,使用简单的数组和找到的元素的标志。

    你可以使用顺序不变的hash算法,与滑动窗口一起工作,以稍微优化事情

    这种散列算法的一个例子可以是

    int hash(string s){
        int result = 0;
    
        for(int i = 0; i < s.length(); i++)
            result += s[i];
    
        return result;
    }
    
    在该算法中使用滑动窗口非常简单:

    string s = "abcd";
    
    hash(s.substring(0, 3)) + 'd' - 'a' == hash(s.substring(1, 3));
    
    这种散列方法的这两个特性允许我们执行如下操作:

    int hash(string s){
        return sum(s.chars);
    }
    
    int slideHash(int oldHash, char slideOut, char slideIn){
        return oldHash - slideOut + slideIn;
    }
    
    int findPermuted(string s, string pattern){
        int patternHash = hash(pattern);
        int slidingHash = hash(s.substring(0, pattern.length()));
    
        if(patternHash == slidingHash && isPermutation(pattern, s.substring(0, pattern.length())
            return 0;
    
        for(int i = 0; i < s.length() - pattern.length(); i++){
            slidingHash = slideHash(slidingHash, s[i], s[i + pattern.length()]);
    
            if(patternHash == slidingHash)
                if(isPermutation(pattern, s.substring(i + 1, pattern.length())
                    return i + 1;
        }
    
        return -1;
    }
    
    map<char, int> primes = generatePrimTable();
    map<int, int> inverse = generateMultiplicativeInverses(primes);
    
    unsigned int hash(string s){
        unsigned int hash = 1;
        for(int i = 0; i < s.length(); i++)
            hash *= primes[s[i]];
    
        return hash;
    }
    
    unsigned int slideHash(unsigned int oldHash, char slideOut, char slideIn){
        return oldHash * inverse[primes[slideOut]] * primes[slideIn];
    }
    
    请记住,此解决方案适用于无符号整数。

    典型的字谜滚动哈希函数

    • 素数乘积的应用
    • 这只适用于相对较短的模式
    • 所有普通字的哈希值都将适合64位值,而不会溢出

    /*braek*/
    /*“foobaroofzaqofom”*/
    #包括
    #包括
    #包括
    typedef无符号长HashVal;
    静态HashVal hashchar(无符号字符ch);
    静态HashVal hashmem(void*ptr,size\u t len);
    无符号字符素数26[]=
    { 5,71,79,19,2,83,31,43,11,53,37,23,41,3,13,73,101,17,29,7,59,47,61,97,89,67, };
    /*********************************************/
    静态HashVal hashchar(无符号字符ch)
    {
    HashVal=1;
    如果(ch>='A'&&ch='A'&&ch'z'){pos=0;rothash=1;continue;}
    如果(ch>'Z'&&ch<'a'){pos=0;rothash=1;continue;}
    /*从滚动哈希中删除旧字符*/
    如果(pos>=patlen){rothash/=hashchar(buff[rotor]);}
    /*向滚动哈希添加新字符*/
    buff[转子]=ch;
    rothash*=hashchar(buff[转子]);
    //fprintf(标准字符,“%zu:[rot=%zu]pos=%zu,Hash=%llx\n”,len,rotor,pos,rothash);
    转子=(转子+1)%patlen;
    /*匹配足够多的字符*/
    如果(++pos

    输出/结果:


    $。/a.out foo

    更新。对于不喜欢素数乘积的人,下面是一个立方体数和(+附加直方图检查)实现。这也应该是8位干净的。注:立方体不是必需的;它与正方形同样适用。或者只是总数。(最后的直方图检查还有一些工作要做)


    /*braek*/
    /*“foobaroofzaqofom”*/
    #包括
    #包括
    #包括
    typedef无符号长HashVal;
    静态HashVal hashchar(无符号字符ch);
    静态HashVal hashmem(void*ptr,size\u t len);
    /*********************************************/
    静态HashVal hashchar(无符号字符ch)
    {
    HashVal=1+ch;
    返回val*val*val;
    }
    静态HashVal hashmem(void*ptr,size\u t len)
    {
    尺寸(idx);;
    无符号字符*str=ptr;
    HashVal=1;
    如果(!len)返回0;
    对于(idx=0;idx=patlen){
    rothash-=hashchar(cycbuff[rotor]);
    rothist[cycbuff[转子]]-=1;
    }
    /*向滚动哈希添加新字符*/
    cycbuff[转子]=ch;
    rothash+=hashchar(cycbuff[rotor]);
    rothist[cycbuff[转子]]+=1;
    //fprintf(标准,“%zu:[rot=%zu],Hash=%llx\n”,len,rotor,rothash);
    转子
    
    map<char, int> primes = generatePrimTable();
    map<int, int> inverse = generateMultiplicativeInverses(primes);
    
    unsigned int hash(string s){
        unsigned int hash = 1;
        for(int i = 0; i < s.length(); i++)
            hash *= primes[s[i]];
    
        return hash;
    }
    
    unsigned int slideHash(unsigned int oldHash, char slideOut, char slideIn){
        return oldHash * inverse[primes[slideOut]] * primes[slideIn];
    }
    
    /* braek; */
    /* 'foobaroofzaqofom' */
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    typedef unsigned long long HashVal;
    static HashVal hashchar (unsigned char ch);
    static HashVal hashmem (void *ptr, size_t len);
    
    unsigned char primes26[] =
    { 5,71,79,19,2,83,31,43,11,53,37,23,41,3,13,73,101,17,29,7,59,47,61,97,89,67, };
    /*********************************************/
    static HashVal hashchar (unsigned char ch)
    {
    HashVal val=1;
    
    if (ch >= 'A' && ch <= 'Z' ) val = primes26[ ch - 'A'];
    else if (ch >= 'a' && ch <= 'z' ) val = primes26[ ch - 'a'];
    
    return val;
    }
    
    static HashVal hashmem (void *ptr, size_t len)
    {
    size_t idx;
    unsigned char *str = ptr;
    HashVal val=1;
    
    if (!len) return 0;
    for (idx = 0; idx < len; idx++) {
            val *= hashchar ( str[idx] );
            }
    
    return val;
    }
    /*********************************************/
    
    
    unsigned char buff [4096];
    int main (int argc, char **argv)
    {
    size_t patlen,len,pos,rotor;
    int ch;
    HashVal patval;
    HashVal rothash=1;
    
    patlen = strlen(argv[1]);
    patval = hashmem( argv[1], patlen);
    // fprintf(stderr, "Pat=%s, len=%zu, Hash=%llx\n", argv[1], patlen, patval);
    
    for (rotor=pos=len =0; ; len++) {
            ch=getc(stdin);
            if (ch == EOF) break;
    
            if (ch < 'A' || ch > 'z') { pos = 0; rothash = 1; continue; }
            if (ch > 'Z' && ch < 'a') { pos = 0; rothash = 1; continue; }
                    /* remove old char from rolling hash */
            if (pos >= patlen) { rothash /= hashchar(buff[rotor]); }
                    /* add new char to rolling hash */
            buff[rotor] = ch;
            rothash *= hashchar(buff[rotor]);
    
            // fprintf(stderr, "%zu: [rot=%zu]pos=%zu, Hash=%llx\n", len, rotor, pos, rothash);
    
            rotor = (rotor+1) % patlen;
                    /* matched enough characters ? */
            if (++pos < patlen) continue;
                    /* correct hash value ? */
            if (rothash != patval) continue;
            fprintf(stdout, "Pos=%zu\n", len);
            }
    
    return 0;
    }
    
    $ ./a.out foo < anascan.c
    Pos=21
    Pos=27
    Pos=33
    
    /* braek; */
    /*  'foobaroofzaqofom' */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    typedef unsigned long long HashVal;
    static HashVal hashchar (unsigned char ch);
    static HashVal hashmem (void *ptr, size_t len);
    
    /*********************************************/
    static HashVal hashchar (unsigned char ch)
    {
    HashVal val=1+ch;
    
    return val*val*val;
    }
    
    static HashVal hashmem (void *ptr, size_t len)
    {
    size_t idx;
    unsigned char *str = ptr;
    HashVal val=1;
    
    if (!len) return 0;
    for (idx = 0; idx < len; idx++) {
            val += hashchar ( str[idx] );
            }
    
    return val;
    }
    /*********************************************/
    int main (int argc, char **argv)
    {
    size_t patlen,len,rotor;
    int ch;
    HashVal patval;
    HashVal rothash=1;
    unsigned char *patstr;
    unsigned pathist[256] = {0};
    unsigned rothist[256] = {0};
    unsigned char cycbuff[1024];
    
    patstr = (unsigned char*) argv[1];
    patlen = strlen((const char*) patstr);
    patval = hashmem( patstr, patlen);
    
    for(rotor=0; rotor < patlen; rotor++) {
            pathist [ patstr[rotor] ] += 1;
            }
    fprintf(stderr, "Pat=%s, len=%zu, Hash=%llx\n", argv[1], patlen, patval);
    
    for (rotor=len =0; ; len++) {
            ch=getc(stdin);
            if (ch == EOF) break;
    
                    /* remove old char from rolling hash */
            if (len >= patlen) {
                    rothash -= hashchar(cycbuff[rotor]);
                    rothist [ cycbuff[rotor] ] -= 1;
                    }
                    /* add new char to rolling hash */
            cycbuff[rotor] = ch;
            rothash += hashchar(cycbuff[rotor]);
            rothist [ cycbuff[rotor] ] += 1;
    
            // fprintf(stderr, "%zu: [rot=%zu], Hash=%llx\n", len, rotor, rothash);
    
            rotor = (rotor+1) % patlen;
                    /* matched enough characters ? */
            if (len < patlen) continue;
                    /* correct hash value ? */
            if (rothash != patval) continue;
                    /* correct histogram? */
            if (memcmp(rothist,pathist, sizeof pathist)) continue;
            fprintf(stdout, "Pos=%zu\n", len-patlen);
            }
    
    return 0;
    }