61、腾讯现场招聘问题
liuchen1206
今天参加了腾讯的现场招聘会,碰到这个一个题目:
  在一篇英文文章中查找指定的人名,人名使用二十六个英文字母(可以是大写或小写)、空格以及两个通配符组成(*、?),通配符“*”表示零个或多个任意字母,通配符“?”表示一个任意字母。
如:“J* Smi??” 可以匹配“John Smith” .

请用C语言实现如下函数:
void scan(const char* pszText, const char* pszName);
注:pszText为整个文章字符,pszName为要求匹配的英文名。
请完成些函数实现输出所有匹配的英文名,除了printf外,不能用第三方的库函数等。

我的思路:

将输入的目标字符串划分为关键子字符串和分隔字符串

例如:输入的目标字符串为 J*?Smi?? ,则有2个关键子字符串为 J 、Smi ,2个分隔字符串*?、??,第一个分隔字符串表示在第一个关键子字符串与第二个子关键字符串之间至少有1个字符,第二个分隔字符串表示在第二个子字符串之后必须有2个字符

注意:目标字符串的开始和结尾不能包含*,因为是无效的。例如 *?Smi?*?*,则此目标字符串等效于 ?Smi??

算法流程:

1、将输入的目标字符串划分为K个关键子字符串和K+1个分隔字符串

2、使用KMP字符匹配算法,分别匹配K个关键子字符串,将结果关键子字符串的位置分别保存在K个数组中

3、计算K+1个分隔字符串表示的最少字符;计算方法是只有有*就表示>=0, 有N个?,则表示>=N

1)只有*,则 >=0

2)只有?,则==N

3)有*,?,则>=N

4、定义Li 为第 i 个关键子字符串的匹配个数,

先比较第一个关键子字符串前面的字符个数是否满足第一个分隔字符串的条件,若满足则

判断第i个关键子字符串与第i+1个关键子字符串之间是否满足第i+1个分隔字符串的条件,若满足则继续判断,

直到第K个关键子字符串后面的字符满足第K+1个分隔字符串的条件,则输出当前字符串,从第一个关键子字符串的第一个字符到第K个关键子字符串的最后一个字符,另外若第1个和第K+1分隔字符串中有Ni 和 N k+1个?,则还要输出前面的Ni 和后面的N k+1个字符。

5,结束


实现:

1、KMP字符串匹配函数

dataChar 待匹配的字符串, object 目标字符串, 匹配上的字符串的坐标,从0开始,

// maxMatchNum 最多能记录的匹配数,是matchIndex 数组长度,

// 返回值,若超过最大匹配数则返回 -1,若没有匹配的则返回0,否则返回匹配的个数

int KMPMatch(const char * dataChar, const char * object, int * matchIndex, int maxMatchNum)

2、目标字符串解析

inObjectString, 关键子字符串 subKeyString,

例如:inObjectString=“ J*Smi??” 则subKeyString={'J',‘\0’,‘S’,‘m’,‘i’,‘\0’,};  subKenCharNum={1, 3}; subKeyStringNum =2;

divAsk ={0, 0, 2}; divNum=3;

int parseObjectString(const char * inObjectString, char * subKeyString, int * subKenCharNum, int subKeyStringNum, int * divAsk int * divNum)

匹配第i个关键子字符串

subKeyStringStart={0,2}

匹配第i个关键子字符串

 KMPMatch(dataChar, subKeyString[ subKeyStringStart[i] ], matchIndex, maxMatchNum)


4、根据匹配结果输出整个目标字符串的匹配结果

void checkObjectString()

KMP实现:

【C代码-KMP】http://www-igm.univ-mlv.fr/~lecroq/string/node8.html

void preKmp(char *x, int m, int kmpNext[]) {
   int i, j;

   i = 0;
   j = kmpNext[0] = -1;
   while (i < m) {
      while (j > -1 && x[i] != x[j])
         j = kmpNext[j];
      i++;
      j++;
      if (x[i] == x[j])
         kmpNext[i] = kmpNext[j];
      else
         kmpNext[i] = j;
   }
}
void KMP(char *x, int m, char *y, int n) {
   int i, j, kmpNext[XSIZE];

   /* Preprocessing */
   preKmp(x, m, kmpNext);

   /* Searching */
   i = j = 0;
   while (j < n) {
      while (i > -1 && x[i] != y[j])
         i = kmpNext[i];
      i++;
      j++;
      if (i >= m) {
         OUTPUT(j - i);
         i = kmpNext[i];
      }
   }
}