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

Given a word and a text, we need to return the occurrences of anagrams

本文关键字:一个 返回 单词 文本 我们      更新时间:2023-10-16

给定一个单词和一个文本,返回文本中单词字谜的出现次数。例如。单词是"for",文本是"forxxorfxdofr","for"的字谜将是"ofr","orf","fro"等。因此,对于这个特定示例,答案将是 3。

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

您可以简单地查找字符数。

例如,假设您正在寻找look字谜。因此,您正在寻找:

  • 一个4个字符长的单词,
  • 使用 1 L、2 O 和 1 K。

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

TooTone的O(n)解决方案必须为输入文本的每个字符比较两个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] != ''; 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] != ''; 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;
    }
}

从本质上讲,您可以在输入上滑动单词长度的窗口,并计算窗口中每个字母的数量。当滑动窗口中的字母计数与单词的字母计数匹配时,您就有了匹配项。

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

您要做的是前进curr,并通过减少从滑动窗口背面掉出的字母并增加出现在滑动窗口前面的字母计数来使数组windCounts最新。(显然,直到curr> 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;
}

我取了两个字符串,即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;
}  
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
这是我

在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;