:字符串包含
Posted 骨灵冷
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:字符串包含相关的知识,希望对你有一定的参考价值。
题目描述:有一个较长的字符串A和较短的字符串B,如何快速查找是否A全部包含B,即B字符串里的字符A中都有。注意:不用顺序一致,只要包含即可。
如:StringA:ABCDEFGHLMNOPQRS
StringB:DCGSRQPO
则返回true。
思路1:
看到这题,我的第一反应就是逐个比较(毕竟我的经验不多,想法比较单纯~~~)。获取A和B两个字符串的长度,假设B较短,则把B中的字符一个个提取出来与A中的进行比较。如果length(A) = m,length(B) = n,且m>n,则最坏情况下时间复杂度是O(n*m)。这样的方法效率比较低,想想有木有改善的地方?
思路1的代码如下:
#include <iostream>
#include <stdio.h>
using namespace std;
bool compare_chars(char* str1,char* str2);
int get_char_length(char* str);
int main()
char A[] = "ABCDEFGHLMNOPQRS";
char B[] = "DCGSRQPOZ";
printf("A的长度是%d\\nB的长度是%d\\n",get_char_length(A),get_char_length(B));
bool isCompare = compare_chars(A,B);
if(isCompare)
printf("包含");
else
printf("不包含");
getchar();
return 0;
int get_char_length(char* str)
if(str == NULL)
return -1;
else
int length = 0;
while (str[length++] != '\\0');
return length-1;
//思路1
bool compare_chars(char* str1,char* str2)
char temp;
const int length_A = get_char_length(str1);
const int length_B = get_char_length(str2);
for (int i = 0 ;i < length_B;i++)
temp = *(str2+i);
int j = 0;
while(temp != *(str1 + j) && j < length_A)
j++;
if(length_A == j)
return false;
return true;
思路2:
可以先把两个字符串进行排序,好的排序算法可以降低时间复杂度,而排序完成之后就可以对两个字符串进行轮询扫描。假设两个字符串是从小到大进行排序的,再进行扫描时,先建立两个指针分别指向两个字符串的起点(pA,pB)
如果*(pA) < *(pB) 则pB不动,pA++向后移动
如果*(pB) < *(pA) 则pA不动,pB++向后移动
如果B字符串中有一个字符是未在A中发现与其相等的字符(即*(pA) < *(pB)时,pA++,然后*(pA) > *(pB),此时表示pB未等于过,所以pB查找失败),B字符串后续的字符也不用进行查询了。
最坏情况下是O(m+n)的时间复杂度。
加上排序所消耗的时间复杂度,总体时间复杂度 应该是O(mlongm)+O(nlogn)+O(m+n)
思路2的代码如下:
//思路2
void quick_sort(char*str,int left,int right)
char f,t;
int rtemp,ltemp;
rtemp = right;
ltemp = left;
f = *(str + (left + right)/2);
while(ltemp < rtemp)
while(*(str + ltemp) < f)
++ltemp;
while(*(str + rtemp) > f)
--rtemp;
if (ltemp < rtemp)
t = *(str+ltemp);
*(str+ltemp) = *(str+rtemp);
*(str+rtemp) = t;
++ltemp;
--rtemp;
if (ltemp == rtemp)
ltemp++;
if (left < rtemp)
quick_sort(str,left,ltemp-1);
if (right > ltemp)
quick_sort(str,rtemp+1,right);
bool compare_chars(char* str1,char* str2)
//1 先进行排序---快速排序
const int length_A = get_char_length(str1);
const int length_B = get_char_length(str2);
quick_sort(str1,0,length_A-1);
quick_sort(str2,0,length_B-1);
//2 轮询比较
int i = 0, j = 0;
while(i<length_A && j < length_B)
if(*(str1+i) < *(str2+j))
i++;
else if(*(str1+i) == *(str2+j))
if (i == length_A - 1 && j == length_B - 1)
return true;
else
j++;
i++;
else
return false;
if (str1[i] == '\\0')
return false;
return true;
思路3:
既然思路2的时间复杂度是O(mlogm)+O(nlogn)+O(m+n),那么有没有可能将时间复杂度极限成O(m+n)?是不是可以使用第三方存储空间?有些算法不允许使用。所以我就在想,既然是大写英文字符,那么最多就是26个,如果先把B字符串里的字符全部记录下来,再让A来比较就好了,只不过这需要中间的一个桥梁,毕竟进行B标记的与A比较的应该相同。所以可以构建一个数组,长度为26(26是个关键长度)。
初始化:int position[26] = 0;
针对B字符串的对应的26个英文字母的序号填充position数组,若出现,则将值置为1,否则保持0,最后记录长度为m。
序列完B之后,将A的字符也进行比较,如果也出现同样的字符,则将1置为0,同时m-1,如果未出现,则保持不变。
最后检测m的长度是否为0,如果不为0,说明false,反正为true.
这就实现了对每个字符串里的字符只访问一次。
思路3的代码如下:
后来发现这就是hashtable的想法啊,= =!!!-。-
int main()
string str1="ABCDEFGHLMNOPQRS";
string str2="DCGSRQPOM";
// 开辟一个辅助数组并清零
int hash[26] = 0;
// num为辅助数组中元素个数
int num = 0;
// 扫描短字符串
for (int j = 0; j < str2.length(); j++)
// 将字符转换成对应辅助数组中的索引
int index = str1[j] - 'A';
// 如果辅助数组中该索引对应元素为0,则置1,且num++;
if (hash[index] == 0)
hash[index] = 1;
num++;
// 扫描长字符串
for (int k = 0; k < str1.length(); k++)
int index = str1[k] - 'A';
// 如果辅助数组中该索引对应元素为1,则num--;为零的话,不作处理(不写语句)。
if(hash[index] ==1)
hash[index] = 0;
num--;
if(num == 0) //m==0,即退出循环。
break;
// num为0说明长字符串包含短字符串内所有字符
if (num == 0)
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
思路4
思路4之所以用蓝色标记是有因为这并不是我想出来的,但是它实在很巧妙,重要的是该方法的确是上一个方法的提升,弥补了上一个办法的缺点。 我们先讨论下上一个方法,如果采用上一个方法,我们必须进行扫描完全才可以,就是说进行A字符串扫描的时候必须全部扫描完,除非事先先将A数据进行排序,那么就可以在第一个position[index] = 1不被置为0的情况下就将结果置为false。不然的话你会发现不排序的A数组后面可能还有机会能将这个地方的1置为0。但是排序会提高时间复杂度。所以有没有更好的方法能够提前作出预判? 这篇文章的方法就很好的解决了这个问题,它的思路如下:1、首先定义最小的26个素数分别与字符'A'到‘Z’对应。 2、遍历A字符串,求得每个字符对应的素数值,获得乘积result。 3、将此乘积去除以B字符对应的素数,如果有余数,则表示B数组的这个素数没在A里出现过,意思就是B的字符没出现在A中,则返回false 4、输出结果 相信各位已经明白了,巧妙的采用素数的方法来暗指字符,采用乘积来描述一个序列,采用余数来进行判断。以上两种方法都有一个共同点,就是寻求适合两者的一个共同标准,当A满足了标准而B却向矛盾时,则over。这是算法的入口。
思路4 的代码如下:
#include <iostream>
#include <string>
#include "BigInt.h"
using namespace std;
// 素数数组
int primeNumber[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, 97, 101;
int main()
string strOne = "ABCDEFGHLMNOPQRS";
string strTwo = "DCGSRQPOM";
// 这里需要用到大整数
CBigInt product = 1; //大整数除法的代码,下头给出。
// 遍历长字符串,得到每个字符对应素数的乘积
for (int i = 0; i < strOne.length(); i++)
int index = strOne[i] - 'A';
product = product * primeNumber[index];
// 遍历短字符串
for (int j = 0; j < strTwo.length(); j++)
int index = strTwo[j] - 'A';
// 如果余数不为0,说明不包括短字串中的字符,跳出循环
if (product % primeNumber[index] != 0)
break;
// 如果积能整除短字符串中所有字符则输出"true",否则输出"false"。
if (strTwo.length() == j)
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
以上是关于:字符串包含的主要内容,如果未能解决你的问题,请参考以下文章