字符串包含问题

字符串包含问题:


(一)问题:
有一个字符串A,字符串B,字符串B较短,查看B中的字符是否都在A中?
如:String 1: ABCDEFGHLMNOPQRS
String 2: DCGSRQPO
答案是true,所有在string2 里的字母string1 也都有。


(1)方法一:O(m*n):
针对str2中的每一个字符,一一与第一个字符串str1中的每个字符依次轮询比较,看是否在str1中出现:


代码实现:
#include <iostream>
using namespace std;
#include <string>


int compareString(String str1,String str2){
int len1=str1.length();
int len2=str2.length();
int i,j;
for(i=0;i<len2;i++){//对于短字符串中的每一个字符,看是否在str1中。
for(j=0;j<len1;j++){
if(str2[i]==str1[j])
break;
}


if(j==len1) return 0;


}
return 1;
}


--------
(2)方法二:O(mlogm)+O(nlogn)+O(m+n)的排序方法:


先对这两个字符串的字母进行排序,然后同时对两
个字串依次轮询。两个字串的排序需要(常规情况)O(m log m) + O(n log n)次
操作,之后的线性扫描需要O(m+n)次操作。


---------


(3)O(n+m)的计数排序方法:


// 计数排序,O(n+m)
void CounterSort(string str, string &help_str){
// 辅助计数数组
int help[26] = {0};
// help[index]存放了等于index + 'A'的元素个数
for (int i = 0; i < str.length(); i++){
int index = str[i] - 'A';
help[index]++;
}
// 求出每个元素对应的最终位置
for (int j = 1; j < 26; j++)
help[j] += help[j-1];
for (int k = str.length() - 1; k >= 0; k--)
{
int index = str[k] - 'A';
int pos = help[index] - 1;
help_str[pos] = str[k];
help[index]--;
}
}


//线性扫描O(n+m)
void Compare(string long_str,string short_str)
{
int pos_long = 0;
int pos_short = 0;
while (pos_short < short_str.length() && pos_long < long_str.length())
{
// 如果pos_long 递增直到long_str[pos_long] >= short_str[pos_short]
while (long_str[pos_long] < short_str[pos_short] 
&& pos_long < long_str.length() - 1)
pos_long++;
// 如果short_str 有连续重复的字符,pos_short 递增
while (short_str[pos_short] == short_str[pos_short+1])
pos_short++;
if (long_str[pos_long] != short_str[pos_short])
break;
pos_long++;
pos_short++;
}
if (pos_short == short_str.length())
cout << "true" << endl;
else
cout << "false" << endl;
}
--------
(4)方法四:O(n+m)的hashtable 的方法:


1)步骤:


1、hash[26],先全部清零,然后扫描短的字符串,若有相应的置1,
2、计算hash[26]中1 的个数,记为m
3、扫描长字符串的每个字符a;若原来hash[a] == 1 ,则修改hash[a] = 0,
并将m 减1;若hash[a] == 0,则不做处理
4、若m == 0 or 扫描结束,退出循环。




2)代码实现:


#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;
}




--
hash方法二:




#include<iostream>
#include<string.h>
using namespace std;


int main()
{
char long_ch[]="ABCDEFGHLMNOPQRS";
char short_ch[]="DEFGHXLMNOPQ";
int i;
bool store[58];
memset(store,false,58);
//前两个是遍历两个字符串, 后面一个是遍历数组
for(i=0;i<sizeof(short_ch)-1;i++)
store[short_ch[i]-65]=true;
for(i=0;i<sizeof(long_ch)-1;i++)
{
if(store[long_ch[i]-65]!=false)
store[long_ch[i]-65]=false;
}


for(i=0;i<58;i++)
{
if(store[i]!=false)
{
cout<<"short_ch is not in long_ch"<<endl;
break;
}
if(i==57)
cout<<"short_ch is in long_ch"<<endl;
}
return 0;
}


----
(6)方法五:O(n)到O(n+m)的素数方法:


1)思想:


有一个一定个数的字母组成字串,我给每个字母分配一个素数,从
2 开始,往后类推。这样A 将会是2,B 将会是3,C 将会是5,等等。遍
历第一个字串,把每个字母代表的素数相乘。然后——轮询第二个字符串,用每个字母除它。如果除的结果有余数,这说明有不匹配的字母。如果整个过程中没有余数,你应该知道它是第一个字串恰好的子集了。




2)步骤:
1.定义最小的26 个素数分别与字符'A'到'Z'对应。
2.遍历长字符串,求得每个字符对应素数的乘积。
3.遍历短字符串,判断乘积能否被短字符串中的字符对应的素数整除。
4.输出结果。


3)分析:
上述算法的时间复杂度为O(m+n),时间复杂度最好的情况
为O(n)(遍历短的字符串的第一个数,与长字符串素数的乘积相除,即出现余
数,便可退出程序,返回false),n 为长字串的长度。不考虑大数据的问题。


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;
}


if (strTwo.length() == j)
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
}


---


5)改进:
1.只考虑大写字符,如果考虑小写字符和数组的话,素数数组需要更多素数
2.没有考虑重复的字符,可以加入判断重复字符的辅助数组。


假设字母都由大写字母组成……,我们先对小字符串预处理,
可以得到B 里包含哪些字符,这里可以用位运算,或者用bool 数组。位运算简
单些,用一个int 中的26bit 表示其是否在B 中出现即可。


//copyright@ caopengcs 2013
//A是否包含B
bool AcontainsB(char *A,char *B) {
int have = 0;
while (*B) {
have |= 1 << (*(B++) - 'A'); // 把A..Z 对应为0..26
}
while (*A) {
if ((have & (1 << (*(A++) - 'A'))) == 0) {
return false;
}
}
return true;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值