程序员编程艺术2:字符串是否包含问题

题目描述:假设这有一个各种字母组成的字符串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;  
}  



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值