程序員編程藝術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;  
}  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章