子串搜索面试问题

时间:2010-08-16 21:01:19

标签: c++ c

char* func( char* a, const char* b )
{
    while( *a )
    {
        char *s = a, *t = b;
        while( (*s++ == *t++) && *s && *t );

        if( *t == 0 )
            return a;
        a++;
    }
    return 0;       
}

上面的代码是为了搜索第一个实例而编写的 字符串“a”中的字符串“b”。

上述程序有问题吗?

有没有办法提高效率?

12 个答案:

答案 0 :(得分:11)

如果指向“cat”且b指向“ab”,则func将返回指向“at”(错误值)而不是0(预期值)的指针,因为即使比较,指针t也会递增(* s ++ == * t ++)失败。

为了完整起见,为了回答第二个问题,我提供了一个解决方案(当然还有其他可行的解决方案):将比较结果分配给另一个变量,例如: while( ( flag = ( *s++ == *t++ ) ) && *s && *t );然后if( flag && *t == 0 )

答案 1 :(得分:5)

我不是C开发人员所以我不能也不会评论代码的正确性,但关于效率,请参阅:

http://en.wikipedia.org/wiki/String_searching_algorithm

我相信你有天真的搜索版本。看看Knuth-Morris-Pratt算法。在b中搜索之前,您可以对字符串a执行一些操作。然后你可以在O(|a|+|b|)中完成。 |b|大于|a|b不能a,因此它变为O(|a|)

本质是如果a是:

abcabe

b是:

aba

然后你知道如果第三个char失败,那么如果你移动b一个char或两个char,搜索也会失败。因此,您不必检查每个可能的子字符串:

a[1 .. 3] == b
a[2 .. 4] == b
...

O(|a|*|b|)个字符,但只有一个等于O(|a|)

的子集

答案 2 :(得分:2)

...耶

  • t不能被指定为b作为其破坏常量。
  • 它与“b”中的最后一个字符不匹配。

答案 3 :(得分:2)

嗯,它确实存在一个实际上无法正常工作的轻微问题。

尝试使用=“xyz”和b =“xw”运行。当你第一次点击while循环时,x = x,你增加两个指针,然后再循环。然后y!= w,所以你退出循环。但是你已经增加了指针,所以t == 0,你报告一个命中。

通常,无论最后一个字符是否匹配,都会报告匹配。

如果b是1个字符的字符串,则最后一个字符是唯一的字符,因此1个字符的字符串与任何字符匹配。

我建议不要尝试使用带有副作用的单个语句来执行循环。如这个例子所示,这很棘手。即使你做对了,对于那些试图阅读你的代码的人来说也是非常神秘的。

答案 4 :(得分:2)

你可以将'while loop'重写为(不使用flag):

while( (*s == *t) && *s && *t ){
  s++;
  t++;
}

或者使用for循环......下面的代码是从K& R书中复制的'C':

/* strindex: return index of t in s, -1 if none */
int strindex(char s[], char t[])
{
  int i, j, k;
  for (i = 0; s[i] != '\0'; i++) {
  for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
    ;
  if (k > 0 && t[k] == '\0')
  return i;
  }
  return -1;
}

答案 5 :(得分:0)

  • 如果a未正确地以空值终止,则该函数将会死亡。
  • 如果b没有正确地以空值终止,那么该函数可能会死得很厉害。
  • 缩进很奇怪。

答案 6 :(得分:0)

这将完成这项工作,但我有更好的方法来做到这一点。 查看这篇文章: http://en.wikipedia.org/wiki/String_searching_algorithm

答案 7 :(得分:0)

非常挑剔的一点,除了其他人提出的那些:

如果ab都是0长度,则此例程返回NULL。如果它应该遵循strstr的规范,那么在这种情况下它必须返回a。这是有道理的,因为空字符串b确实是空字符串a的子字符串。

答案 8 :(得分:0)

我认为这一行:

while( (*s++ == *t++) && *s && *t );

未定义,因为您在增量之前或增量之后的后增量之后访问变量。

除非他们改变,否则标准的副作用在标准生效时尚未定义。唯一保证的是* s ++将首先访问s然后为下一个语句递增。未定义的是&&和s和&& t看到增量之前或之后的值......

答案 9 :(得分:0)

为什么不为工作使用功能?你知道strstr()吗?

const char* mystrstr(const char* a,const char* b)
{
  size_t blen=strlen(b);
  while( *a )
  {
    if( !strncmp(a,b,blen) )
      return a;
    ++a;
  }
  return 0;       
}

答案 10 :(得分:0)

* t = b; //杀死b的常量.......

同样为了清晰的代码你可以做(​​ a!='\ 0')而不是while(* a) 第二个while语句: while((* s ++ == * t ++)&& * s&& * t); 将失败....尝试采取int flag =(* s ++ = * t ++); 并做一点简化

答案 11 :(得分:0)

效率?这太糟糕了! <这意味着我可以做得更好,但是...我会做同样的事情。 ;)

看看Knuth-Morris-Pratt