挑战面试编程:字符串包含

                        挑战面试编程:字符串包含

    字符串查找是在一个大的文本中查找一个给定的模式串,常用的算法有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;
}


所有内容的目录

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值