挑战面试编程:字符串包含
字符串查找是在一个大的文本中查找一个给定的模式串,常用的算法有KMP、BM、Sunday等。而字符串包含要求比较低:只要字符包含就行,不需要模式串作为整体出现。
例如,S="abcd",T="ac",做查找运算,则T不在S中;做包含运算,T包含在S中。
方法一
最简单的就是对T中的每一个字符都在S中进行查找,都存在,则包含。
/* 字符串包含--朴素法 判断字符串T中的字符是否全都在字符串S中 */ bool contains(char *S, char *T) { assert(S && T); int SLen, TLen; SLen = strlen(S), TLen = strlen(T); int i, j; i = 0, j = 0; while (j < TLen) { i = 0; while (i < SLen) { if (T[j] == S[i]) break; i++; } if (i == SLen) return false; j++; } return true; }在最坏的情况下,对于T中的每一个字符都遍历一遍S,则时间复杂度是O(mn)
方法二
先对对两个字符串排序,排序后再检索,这样的检索效率高。
/* 字符串包含--排序比较法 判断字符串T中的字符是否全都在字符串S中 */ bool contains2(char *S, char *T) { assert(S && T); int SLen, TLen; SLen = strlen(S), TLen = strlen(T); /* 先排序 sort(first, last)函数对[first, last)范围的数据按升序排序 */ sort(S, S + SLen); sort(T, T + TLen); //puts(S); //puts(T); int i, j; i = 0, j = 0; while (j < TLen) { while (i < SLen && S[i] < T[j]) i++; if (i == SLen || S[i] > T[j]) return false; j++; } return true; }S的长度是n,T的长度是m,则排序是O(nlogn+mlogm),检索是O(m+n),时间复杂度是O(nlogn+mlogm+m+n)。排序可采用更高效的计数排序。
方法三
素数法,利用素数特有的性质:除1和本身外再无其它因数。
/* 字符串包含--素数法 判断字符串T中的字符是否全都在字符串S中 */ bool contains3(char *S, char *T) { assert(S && T); int SLen, TLen; SLen = strlen(S), TLen = strlen(T); int prime[26] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 91, 97 }; long long mul = 1; int i, x; for (i = 0; i < SLen; i++) { x = prime[S[i] - 'a']; //为了防止mul过大,去掉重复的素数 if (mul % x) mul *= x; } for (i = 0; i < TLen; i++) if (mul % prime[T[i] - 'a']) return false; return true; }最好O(n),在遍历T的第一个字符时就失败。最坏O(n+m),需要遍历完T。素数法并不完美,素数相乘的乘积可能过大,造成溢出。故效率高,但不推荐使用。
方法四
对两字符串构造位图,然后进行集合的包含运算判断。
/* 字符串包含--位图法 判断字符串T中的字符是否全都在字符串S中 */ bool contains4(char *S, char *T) { assert(S && T); bitset<26> s, t; int SLen, TLen; SLen = strlen(S), TLen = strlen(T); s.reset(); t.reset(); int i; for (i = 0; i < SLen; i++) s.set(S[i] - 'a'); for (i = 0; i < TLen; i++) t.set(T[i] - 'a'); //若S包含T,则集合s包含t //或者return (s.to_ulong() & t.to_ulong()) == t.to_ulong(); return (s.to_ulong() | t.to_ulong()) == s.to_ulong(); }时间复杂度显然是O(m+n)。
方法五
这是位运算法,也叫哈希法,它与位图法本质上是一样的。
/* 字符串包含--位运算法 判断字符串T中的字符是否全都在字符串S中 */ bool contains5(char *S, char *T) { assert(S && T); int SLen, TLen; SLen = strlen(S), TLen = strlen(T); int i, bit; bit = 0; for (i = 0; i < SLen; i++) bit |= (1 << (S[i] - 'a')); for (i = 0; i < TLen; i++) if ((bit & (1 << (T[i] - 'a'))) == 0) return false; return true; }
所有内容的目录