给定一个单词和一个文本,我们需要返回字谜的出现

时间:2013-09-15 10:49:20

标签: c++ algorithm

给定单词和文本,返回文本中单词字符的出现次数。 例如。单词是“for”,文本是“forxxorfxdofr”,“for”的字谜将是“ofr”,“orf”,“fro”等等。所以对于这个特例,答案是3。

我有蛮力方法获得该词的所有排列,然后比较文本是否包含它,并增加出现次数,但这是O(N ^ 2)方法。我正在寻找更好的复杂性。

5 个答案:

答案 0 :(得分:13)

您只需查找字符数即可。

比如说你正在寻找look的字谜。所以,你正在寻找:

  • 4个字符长度字,
  • 1 l,2 o和1 k。

只需处理前4个字母,存储计数。检查您是否匹配。 添加下一个字符(增量),删除旧字符(减量)。再检查一遍。 等等...

答案 1 :(得分:3)

TooTone's O(n) solution必须为输入文本的每个字符比较两个256元素向量。这可以通过跟踪两个矢量不同的位置的数量来避免,并且当该数字变为零时记录匹配。事实上,我们甚至根本不需要存储两个不同的向量,因为我们可以存储一个包含它们差异的向量。

这是我实现这些优化的版本。它是用普通的旧C语言编写的,但应该在C ++下进行适当的调整:

#include <stdio.h>
#include <limits.h> /* for UCHAR_MAX (usually 255) */

int find_anagrams (char *word, char *text) {
    int len = 0;           /* length of search word */
    int bin[UCHAR_MAX+1];  /* excess count of each char in last len chars of text */
    int mismatch = 0;      /* count of nonzero values in bins[] */
    int found = 0;         /* number of anagrams found */
    int i;                 /* generic loop counter */

    /* initialize bins */
    for (i = 0; i <= UCHAR_MAX; i++) bin[i] = 0;
    for (i = 0; word[i] != '\0'; i++) {
        unsigned char c = (unsigned char) word[i];
        if (bin[c] == 0) mismatch++;
        bin[c]--;
        len++;  /* who needs strlen()? */
    }

    /* iterate through text */
    for (i = 0; text[i] != '\0'; i++) {
        /* add next char in text to bins, keep track of mismatch count */
        unsigned char c = (unsigned char) text[i];
        if (bin[c] == 0) mismatch++;
        if (bin[c] == -1) mismatch--;
        bin[c]++;

        /* remove len-th previous char from bins, keep track of mismatch count */
        if (i >= len) {
            unsigned char d = (unsigned char) text[i - len];
            if (bin[d] == 0) mismatch++;
            if (bin[d] == 1) mismatch--;
            bin[d]--;
        }

        /* if mismatch count is zero, we've found an anagram */
        if (mismatch == 0) {
            found++;
#ifdef DEBUG
            /* optional: print each anagram found */
            printf("Anagram found at position %d: \"", i-len+1);
            fwrite(text+i-len+1, 1, len, stdout);
            printf("\"\n");
#endif
        }
    }
    return found;
}


int main (int argc, char *argv[]) {
    if (argc == 3) {
        int n = find_anagrams(argv[1], argv[2]);
        printf("Found %d anagrams of \"%s\" in \"%s\".\n", n, argv[1], argv[2]);
        return 0;
    } else {
        fprintf(stderr, "Usage: %s <word> <text>\n", (argc ? argv[0] : "countanagrams"));
        return 1;
    }
}

答案 2 :(得分:2)

基本上,您可以在输入上滑动单词长度的窗口,并计算窗口中每个字母的数量。当滑动窗口中的字母数与您单词的字母数相匹配时,您就会匹配。

让您的字长为n,您当前的位置为curr。创建一个长度为26的数组或vectorwindCounts。条目windCounts[i]存储从位置看到的字母i th 字母的出现次数curr - n - 1curr

你所做的就是提前curr,并通过减少从滑动窗口后面掉落的字母,并增加字母数量,使数组windCounts保持最新状态。已经出现在滑动窗口的前面。 (显然,直到curr&gt; n,你只需增加,你只需按照你的单词长度建立你的滑动窗口。)

在C ++中,您可以使用vector表示单词中的字母数,以及滑动窗口中的字母数,只需使用vector::operator==即可。

编辑:算法为O(N),其中N是要搜索的文本的长度。这可以从下面的代码中看到,其中为您滑动窗口的每个字母执行循环体。

#include <string>
#include <vector>
#include <algorithm> // for_each 

using std::string;
using std::vector;

#include <iostream>

int main(int argc, char* argv[])
{
    const string text = "forxxorfxdofr";
    const string word = "for"; 

    // Counts of letters in word
    vector<int> wordCounts(256); // optimization: cut down from 256 to 26 
    std::for_each(word.begin(), word.end(), 
        [&] (char c) { wordCounts[c]++; } );

    // Current position of end of sliding window
    string::const_iterator curr = text.begin() + word.size();
    // Initial sliding window counts
    vector<int> windCounts(256);
    std::for_each(text.begin(), curr,
        [&] (char c) { windCounts[c]++; } );

    // Run sliding window over text
    int numMatches = 0;
    while (1) {
        numMatches += wordCounts == windCounts;
        if (curr == text.end()) {
            break;
        }
        windCounts[*(curr - word.size())]--;
        windCounts[*curr]++;
        ++curr;
    }

    std::cout << numMatches << "\n";

    return 0;
}

答案 3 :(得分:0)

我有两个字符串即str和occ。 Str是原始的strin和occ是我们必须找到计数的刺痛。使用strncpy函数我已经将occ的长度,即n个字符复制到一个临时数组中,然后检查它是否是一个occ字符串的排列。

#include<iostream.h>  
#include<conio.h>  
#include<string.h>

int permutate(char str1[],char str2[]);  
int permutate(char str1[],char str2[]) {  
    int c[256]={0},i,j;  
    for(i=0;i<strlen(str1);i++)  
        c[str1[i]]++;      

    for(i=0;i<strlen(str2);i++) {  
        c[str2[i]]--;      
        if(c[str2[i]]<0)   
            return 1;   //not a permutation       
    }  
    return 0;           //permutation   
}  

int main()  {
    //enter code here  
    char str[]="forxxorfxdofr",occ[]="for",temp[10];
    int n,i,x,t=0;   
    n=strlen(occ);
    for(i=0;i<strlen(str);i++) {
        strncpy(temp,str+i,n);    //copy the n char from str to temp
        x=permutate(temp,occ);
        if(x==0)                  //if string is a permutation
            t++;
    }
    cout<<"Count = " << t;
    return 0;
}  

答案 4 :(得分:0)

o(n) solution in Python 

def检查(s1,s2):

function takes in s1 as the text and s2 as the text to be checked from here for


c=0
n=len(s2)
ck=sorted(s2)
mk=''.join(ck)


 this loop will pick from s till the length of s2 that is 'for'



for i,item in enumerate(s1):
    if s1[i] in mk:
        p=s1[i:i+n]
        jk=sorted(p)
        er=''.join(jk)

now just comparing the both sorted strings if they are equal then they were anagram 

        if er == mk:
            c+=1
return c