匹配字符串中的子字符串,允许 1 个字符不匹配
Posted
技术标签:
【中文标题】匹配字符串中的子字符串,允许 1 个字符不匹配【英文标题】:Match sub-string within a string with tolerance of 1 character mismatch 【发布时间】:2011-03-20 13:33:48 【问题描述】:我在 CareerCup.com 上浏览了一些亚马逊面试问题,遇到了一个有趣的问题,但我一直不知道该怎么做。从2天开始,我一直在考虑这个问题。要么我采取了一种方法,要么它是一个真正难以编写的函数。
问题如下:
用 C 语言编写一个函数,可以判断一个字符串是否是另一个字符串的子字符串。请注意,一个字符不匹配 应该被忽略。
A mismatch can be an extra character: ’dog’ matches ‘xxxdoogyyyy’
A mismatch can be a missing character: ’dog’ matches ‘xxxdgyyyy’
A mismatch can be a different character: ’dog’ matches ‘xxxdigyyyy’
问题中没有提到返回值,所以我假设函数的签名可以是这样的:
char * MatchWithTolerance(const char * str, const char * substr);
如果与给定规则匹配,则返回指向字符串中匹配子字符串开头的指针。否则返回 null。
奖金
如果有人也能找到一种通用的方法来将容差设为 n 而不是 1,那就太好了。 在这种情况下,签名将是:
char * MatchWithTolerance(const char * str, const char * substr, unsigned int tolerance = 1);
感谢所有愿意尝试并分享他们成功解决方案的人。
【问题讨论】:
dog
是否也匹配 xxxdogyyy
?
(删除了一组与问题无关的cmets)
【参考方案1】:
这似乎有效,如果您发现任何错误,请告诉我,我会尝试修复它们:
int findHelper(const char *str, const char *substr, int mustMatch = 0)
if ( *substr == '\0' )
return 1;
if ( *str == '\0' )
return 0;
if ( *str == *substr )
return findHelper(str + 1, substr + 1, mustMatch);
else
if ( mustMatch )
return 0;
if ( *(str + 1) == *substr )
return findHelper(str + 1, substr, 1);
else if ( *str == *(substr + 1) )
return findHelper(str, substr + 1, 1);
else if ( *(str + 1) == *(substr + 1) )
return findHelper(str + 1, substr + 1, 1);
else if ( *(substr + 1) == '\0' )
return 1;
else
return 0;
int find(const char *str, const char *substr)
int ok = 0;
while ( *str != '\0' )
ok |= findHelper(str++, substr, 0);
return ok;
int main()
printf("%d\n", find("xxxdoogyyyy", "dog"));
printf("%d\n", find("xxxdgyyyy", "dog"));
printf("%d\n", find("xxxdigyyyy", "dog"));
基本上,我确保只有一个字符可以不同,然后运行对大海捞针的每个后缀执行此操作的函数。
【讨论】:
+1!!这非常有效。我确信我们可以使这个返回指针指向匹配字符串的开头。这也可以通用。非常感谢!如果我遇到任何不匹配的情况,我会回复。 @IVlad 对每个 if else 语句的一些评论将有助于我们轻松理解它。请考虑这样做。【参考方案2】:这与 IT 的一个经典问题有关,称为Levenshtein distance。 请参阅Wikibooks 了解一系列不同语言的实现。
【讨论】:
+1 表示没有编写明显会被抄袭的代码并作为他自己的提交。 不,据我所知,这与 levenshtein 距离无关。这要求子字符串匹配,其中允许 1 个字符不匹配。您如何建议我们为此使用 levenshtein 距离? 我应该更清楚一点。 Levenshtein 的实现并没有解决原来的问题。但是,查看算法,您会发现只需稍作改动即可实现模糊子字符串匹配。同样,互联网已经准备好实现:ginstrom.com/scribbles/2007/12/01/… @Stefan 你为什么在每条该死的评论中都挑剔我?我不会在任何地方提交此代码!你甚至没有正确阅读我的问题。我写道,我正在处理面试问题,发现这很有趣。我试图解决它,但不知何故失败了。为什么你认为我打算抄袭这个?这意味着您甚至不了解现实世界中的面试是如何进行的。没有公司会要求你在手机上写这么大的功能。他们只会要求你在 face-2-face interview 中写这样的代码,你显然不能从 Stack Overflow 复制粘贴。 @Pumbaa 感谢您的意见。我很感激。 +1【参考方案3】:这与早期的解决方案略有不同,但我对这个问题很感兴趣并想试一试。显然如果需要优化,我只是想要一个解决方案。
char *match(char *str, char *substr, int tolerance)
if (! *substr) return str;
if (! *str) return NULL;
while (*str)
char *str_p;
char *substr_p;
char *matches_missing;
char *matches_mismatched;
str_p = str;
substr_p = substr;
while (*str_p && *substr_p && *str_p == *substr_p)
str_p++;
substr_p++;
if (! *substr_p) return str;
if (! tolerance)
str++;
continue;
if (strlen(substr_p) <= tolerance) return str;
/* missed due to a missing letter */
matches_missing = match(str_p, substr_p + 1, tolerance - 1);
if (matches_missing == str_p) return str;
/* missed due to a mismatch of letters */
matches_mismatched = match(str_p + 1, substr_p + 1, tolerance - 1);
if (matches_mismatched == str_p + 1) return str;
str++;
return NULL;
【讨论】:
我还没有尝试过你的解决方案,但非递归方法据说非常困难。 +1 尝试。【参考方案4】:有效地做到这一点有问题吗?
简单的解决方案是循环遍历str
中每个大小为substr
的子字符串,从左到右,如果在比较中只有一个字符不同,则如果当前子字符串返回true。
令 n = str 的大小 设 m = substr 的大小
str中有O(n)
子串,匹配步骤需要时间O(m)
。 Ergo,天真的解决方案及时运行
O(n*m)
【讨论】:
我想,效率不会是他们在问题中测试的主要内容。我还是想说,让我们尝试在 O(n*m) 中完成。 -1 这种方法甚至不接近 IVlad 发布的实际解决方案。【参考方案5】:带有任意编号。公差水平。
适用于我能想到的所有测试用例。大致基于 |/|ad 的解决方案。
#include<stdio.h>
#include<string.h>
report (int x, char* str, char* sstr, int[] t)
if ( x )
printf( "%s is a substring of %s for a tolerance[%d]\n",sstr,str[i],t[i] );
else
printf ( "%s is NOT a substring of %s for a tolerance[%d]\n",sstr,str[i],t[i] );
int find_with_tolerance (char *str, char *sstr, int tol)
if ( (*sstr) == '\0' ) //end of substring, and match
return 1;
if ( (*str) == '\0' ) //end of string
if ( tol >= strlen(sstr) ) //but tol saves the day
return 1;
else //there's nothing even the poor tol can do
return 0;
if ( *sstr == *str ) //current char match, smooth
return find_with_tolerance ( str+1, sstr+1, tol );
else
if ( tol <= 0 ) //that's it. no more patience
return 0;
for(int i=1; i<=tol; i++)
if ( *(str+i) == *sstr ) //insertioan of a foreign character
return find_with_tolerance ( str+i+1, sstr+1, tol-i );
if ( *str == *(sstr+i) ) //deal with dletion
return find_with_tolerance ( str+1, sstr+i+1, tol-i );
if ( *(str+i) == *(sstr+i) ) //deal with riplacement
return find_with_tolerance ( str+i+1, sstr+i+1, tol-i );
if ( *(sstr+i) == '\0' ) //substr ends, thanks to tol & this loop
return 1;
return 0; //when all fails
int find (char *str, char *sstr, int tol )
int w = 0;
while (*str!='\0')
w |= find_with_tolerance ( str++, sstr, tol );
return (w) ? 1 : 0;
int main()
const int n=3; //no of test cases
char *sstr = "dog"; //the substr
char *str[n] = "doox", //those cases
"xxxxxd",
"xxdogxx" ;
int t[] = 1,1,0; //tolerance levels for those cases
for(int i = 0; i < n; i++)
report( find ( *(str+i), sstr, t[i] ), *(str+i), sstr, t[i] );
return 0;
【讨论】:
以上是关于匹配字符串中的子字符串,允许 1 个字符不匹配的主要内容,如果未能解决你的问题,请参考以下文章
40 python 正则表达式 match方法匹配字符串 使用search函数在一个字符串中查找子字
在其他两个保守字符串之间提取字符串并允许 python 或 R 中的不匹配