给定单词和文本,返回文本中单词字符的出现次数

时间:2013-10-03 17:10:34

标签: c++ algorithm

例如。单词为for,文字为forxxorfxdofrfor的字谜将为ofrorffro等。所以答案是对于这个特定的例子来说是3

这是我想出的。

#include<iostream>
#include<cstring>

using namespace std;

int countAnagram (char *pattern, char *text)
{
    int patternLength = strlen(pattern);
    int textLength = strlen(text);

    int dp1[256] = {0}, dp2[256] = {0}, i, j;

    for (i = 0; i < patternLength; i++)
    {
        dp1[pattern[i]]++;
        dp2[text[i]]++;
    }

    int found = 0, temp = 0;

    for (i = 0; i < 256; i++)
    {
        if (dp1[i]!=dp2[i])
        {
            temp = 1;
            break;
        }
    }

    if (temp == 0)
        found++;


    for (i = 0; i < textLength - patternLength; i++)
    {
        temp = 0;
        dp2[text[i]]--;
        dp2[text[i+patternLength]]++;
        for (j = 0; j < 256; j++)
        {
            if (dp1[j]!=dp2[j])
            {
                temp = 1;
                break;
            }
        }
        if (temp == 0)
            found++;
    }
    return found;
}


int main()
{
    char pattern[] = "for";
    char text[] = "ofrghofrof";

    cout << countAnagram(pattern, text);

}

对于上述问题,是否存在更快的算法?

3 个答案:

答案 0 :(得分:0)

大部分时间都用于搜索,因此为了使算法更具时间效率,目标是减少搜索量或优化搜索。

方法1:搜索起始位置表。

创建一个列表向量,每个字母表的一个向量槽。这可以在以后进行空间优化。

每个插槽都会包含文本中的索引列表。

示例文字:forxxorfxdofr

Slot  List  
'f'    0 --> 7 --> 11  
'o'    1 --> 5 --> 10  
'r'    2 --> 6 --> 12  

对于每个单词,在向量中查找字母以获取文本中的索引列表。对于列表中的每个索引,将列表项中的文本字符串位置与单词进行比较。

因此,使用上表和单词“ofr”,第一次比较发生在索引1处,第二次比较发生在索引5处,最后一次比较发生在索引10处。

你可以消除文本索引的近端(索引+字长&gt;文本长度)。

答案 1 :(得分:0)

你可以使用乘法的可交换性,以及原始分解的唯一性。这取决于我之前的回答here

创建从每个字符到素数列表的映射(尽可能小)。对于例如a - &gt; 2,b - &gt; 3,c - &gt; 5等。这可以保存在一个简单的数组中。

现在,将给定的单词转换为与其每个字符匹配的素数的乘法。这个结果将等于该词的任何字谜的类似乘法。

现在扫过数组,并在任何给定的步骤中,保持与最后L个字符匹配的素数的乘法(其中L是单词的长度)。所以,每次你前进,

mul = mul * char2prime(text[i]) / char2prime(text[i-L])

每当这个乘法等于你的单词时 - 增加整个计数器,你就完成了

请注意,此方法适用于短字,但素数乘法可以很快地溢出64b var(大约9-10个字母),因此您必须使用大量数学库来支持更长的单词

答案 2 :(得分:-1)

如果要设计的图案太短以至于搜索它的最佳方式是简单地扫描它,那么该算法是相当有效的。为了允许更长的模式,此处由“for jj”和“for mm”循环表示的扫描可以被更复杂的搜索技术所取代。

// sLine -- string to be searched
// sWord -- pattern to be anagrammed
// (in this pseudo-language, the index of the first character in a string is 0)
// iAnagrams -- count of anagrams found

iLineLim = length(sLine)-1
iWordLim = length(sWord)-1

// we need a 'deleted' marker char that will never appear in the input strings
chNil = chr(0)

iAnagrams = 0 // well we haven't found any yet have we
// examine every posn in sLine where an anagram could possibly start
for ii from 0 to iLineLim-iWordLim do {
  chK = sLine[ii]
  // does the char at this position in sLine also appear in sWord
  for jj from 0 to iWordLim do {
    if sWord[jj]=chK then { 
      // yes -- we have a candidate starting posn in sLine

      // is there an anagram of sWord at this position in sLine
      sCopy = sWord // make a temp copy that we will delete one char at a time
      sCopy[jj] = chNil // delete the char we already found in sLine
      // the rest of the anagram would have to be in the next iWordLim positions
      for kk from ii+1 to ii+iWordLim do {
        chK = sLine[kk]
        cc = false
        for mm from 0 to iWordLim do { // look for anagram char
          if sCopy[mm]=chK then { // found one
            cc = true
            sCopy[mm] = chNil // delete it from copy
            break // out of 'for mm'
          }
        }
        if not cc then break // out of 'for kk' -- no anagram char here
      }
      if cc then { iAnagrams = iAnagrams+1 }

      break // out of 'for jj'
    }
  }
}

-Al。