题目描述:假设这有一个各种字母组成的字符串A,和另外一个字符串B,字符串里B的字母数相对少一些。什么方法能最快的查出所有小字符串B里的字母在大字符串A里都有?原文连接:http://blog.csdn.net/v_july_v/article/details/6347454
比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPO
答案是true,所有在string2里的字母string1也都有。
如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPZ
答案是false,因为第二个字符串里的Z字母不在第一个字符串里。
思路1:最先想到的是循环逐个比较字符,外循环水短字符串,内循环是长字符串,判断短字符串中字符在长字符串中是否存在。
时间复杂度O(n*m)
bool StringCompare(string shortStr,string longStr)
{
for(int i=0;i<shortStr.length();i++)
{
for(int j=0;j<longStr.length();j++)
{
if(longStr[j]==shortStr[j])
{
break;
}
}
if(j==longStr.length())
{
return false;
}
}
return true;
}
思路2:对2个字符串排序后再比较。排序时间复杂度+线性比较时间复杂度O(m+n)。关键在于排序的时间复杂度了。
排序可以有多种方式,这里选择2中。
排序1:快速排序,时间复杂度O(nlog n)+O(mlog m)
int Partation(string &str,int begin,int end)
{
char key =str[end];
int index=begin-1;
for (int i=begin;i<end;i++)
{
if(str[i]<key)
{
index++;
if(index!=i)
{
swap(str[index],str[i]);
}
}
}
if((index+1)!=end)
{
swap(str[index+1],str[end]);
}
return index+1;
}
void StringSort::QuickSort(string & str,int begin,int end)
{
if(begin<end)
{
int index=Partation(str,begin,end);
QuickSort(str,begin,index-1);
QuickSort(str,index+1,end);
}
}
排序2:计数排序,利用hasetable 或者 int数组,类似桶排序,时间复杂度O(m+n)。下面是利用数组的实现:
void StringSort::CountSort(string & str)
{
int a[26]={0};
for(int i=0;i<str.length();i++)
{
int index=str[i]-'A';
a[index]++;
}
//求每个字符的位置
for (int j=1;j<26;j++)
{
a[j]+=a[j-1];
}
string str2=str;
for (int k=0;k<str2.length();k++)
{
int s=str2[k]-'A';
int pos=a[s]-1;
str[pos]=str2[k];
a[s]--;
}
}
思路3:同思路2类似,利用int数组或者hasetable,但不排序,利用bool标记,先把短字符放进容器,值为1。然后遍历场长字符,容器中有的值就改为0。最后根据容器中是否还有值为1来判断是否包含。时间复杂度O(m+n)
#include <iostream>
#include <string>
using namespace std;
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:素数,为每个字符分配一个素数,先求长字符素数相乘的积,然后逐个除短字符对于的素数,如果不恩整除,说明不包含。时间复杂度为0(m+n)引用原作者的代码实现
#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;
}