c++ 给定一个单词和一个文本,我们需要返回出现的变位词

qyuhtwio  于 2022-11-19  发布在  其他
关注(0)|答案(6)|浏览(141)

给定一个单词和一个文本,返回该单词在文本中出现的变位词的计数。例如,单词是“for”,文本是“forxxorfxdofr”,“for”的变位词将是“ofr”,“orf”,“fro”等。因此,对于这个特定的例子,答案是3。
我已经得到了蛮力的方法,这是获得所有的排列的单词,然后比较如果文本包含它,并增加出现的次数,但这是O(N^2)的方法。我正在寻找一个更好的复杂性。

kx1ctssn

kx1ctssn1#

您可以简单地查找字符计数。
例如,假设您正在寻找look的字谜。因此,您正在寻找:

  • 4字符长度字,
  • 有1L、2O和1K。

简单地处理前4个字母,存储计数。检查是否有匹配。添加下一个字符(递增),删除旧字符(递减)。再次检查。依此类推...

lp0sw83n

lp0sw83n2#

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;
    }
}
dly7yett

dly7yett3#

基本上,你可以在输入的单词上滑动一个单词长度的窗口,并记录窗口中每个字母的数量。当滑动窗口中的字母数量与单词的字母数量相匹配时,你就有了匹配。
设单词长度为n,当前位置为curr,创建一个长度为26的数组vectorwindCounts,其中windCounts[i]存储从curr - n - 1curr的字母表中第i个字母的出现次数。
你要做的就是把curr向前推进,并保持数组windCounts是最新的,方法是减少从滑动窗口后面掉出来的字母,增加出现在滑动窗口前面的字母数。(很明显,直到currn,你只是增加,你只是建立你的滑动窗口的长度你的话。)
在C++中,你可以使用vector来计算单词中的字母数,以及滑动窗口中的字母数,只需使用vector::operator==来计算等式。

  • Edit*:算法是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;
}
lrl1mhuk

lrl1mhuk4#

我取了两个字符串str和occ。Str是原始字符串,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;
}
3ks5zfa0

3ks5zfa05#

o(n) solution in Python

延迟检查(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
oyxsuwqo

oyxsuwqo6#

这是我用C++编写的解决方案。
它将生成所有排列替换为对单词和字符串的一部分进行排序。

cin >> sstring;
        cin >> word;

        ocurrences = 0;

        sort(word.begin(), word.end());

        for (int i = 0; i < sstring.size(); i++)
        {
            string copy = sstring.substr(i, word.size());

            sort(copy.begin(), copy.end());

            if (word == copy)
            {
                ocurrences++;
            }
        }

        cout << ocurrences << endl;

相关问题