題目:在字串中找出第一個只出現一次的字元。如輸入“abaccdeff”,則輸出‘b’。
方法1:
看到這個題目,最直觀的想法就是就是遍曆法,也就是從頭開始取字串中的一個字元,將其與其後的所有字元比較,如果有相同的字元,那麼就證明它不是只出現一次的字元。當第一次出現遍曆完其後字元並且沒有重複時,表明這個字元就是“第一個只出現一次的字元”。如果字串有n個字元,每個字元可能與後面的O(n)個字元相比較,因此這種思路的時間複雜度是O(n2)。
方法2:
題目中要求第一個只出現一次的字元,那麼就跟字元出現的次數有關。我們考慮如何統計字元出現的次數,然後找出第一個次數為1的那個字元。這裡我們需要一個資料容器來儲存字元出現次數,並且能夠通過字元找出其相對應的次數。雜湊表就是一種常用用的容器。
我們可以定義雜湊表的索引值(Key)是字元的ASCII值,而值(Value)是該字元出現的次數。同時我們需要掃描兩次字串,第一次掃描字串時,每掃描到一個字元就在雜湊表的對應項中把次數加1。接下來第二次掃描的時候,沒掃描到一個字元就能在雜湊表中得到該字元出現的次數。找出第一個Value為1的那個key就是我們需要找到那個字元。
方法1和方法2的代碼實現View Code
#include<iostream>#include<stdlib.h>using namespace std;//O(n^n)的時間複雜度char FirstNotRepeatingChar2(char *pString){ //如果是null 指標,返回\0 if(pString==NULL) return '\0'; int len=strlen(pString); for(int i=0;i<len;i++) { int flag=0;//標識位,0表示這個字元只出現一次。 for(int j=i+1;j<len;j++) { if(pString[i]==pString[j]) { flag=1;//1表示在當前字元後面存在於該字元相同的字元。 } } if(flag==0) return pString[i]; } return '\0';}//O(n)的時間複雜度char FirstNotRepeatingChar(char *pString){ //如果是null 指標,返回\0 if(pString==NULL) return '\0'; //定義hash表長度256,並建立雜湊表 const int len=256; int hashtable[len]; for(int i=0;i<len;i++) { hashtable[i]=0; } char *pHashkey=pString; //第一遍遍曆字串,求出每個字元出現的次數 while((*pHashkey)!='\0') { hashtable[*(pHashkey++)]++; } pHashkey=pString; //第二遍遍曆字串,求出第一個只出現一次的字元,每次都是按照字串的順序遍曆 while((*pHashkey)!='\0') { if(hashtable[*pHashkey]==1) return *pHashkey; pHashkey++; } return '\0';}void main(){ char *pString="abaccdeff"; //cout<<pString<<endl; //cout<<pString[1]<<endl; cout<<sizeof(pString)<<endl;//4 cout<<strlen(pString)<<endl;//9 cout<<FirstNotRepeatingChar(pString)<<endl; cout<<FirstNotRepeatingChar2(pString)<<endl; system("pause");}
字元(char)是一個長度為8bit的資料類型,因此總共最多能夠表示256種字元。所以在前面的程式碼範例中我們直接建立了一個長度為256的整型數組,每個字元根據其ASCII值作為數組的下標對應數組的一個數字,而數組中儲存的是每個字元出現的次數。這樣我們就建立了一個大小為256,以字元ASCII嗎為索引值的雜湊表。
但是假如我們的字串長度小於256,那麼我們可以通過建立一個字串長度的整型數組來存放索引值,索引值是ASCII%len。代碼實現如下:
View Code
char FirstNotRepeatingChar3(char *pString){ //如果是null 指標,返回\0 if(pString==NULL) return '\0'; int len=strlen(pString);//求字串長度 int *hashtable=new int[len];//定義一個動態數組,其長度為字串的長度 //初始化動態數組,初始值為0 for(int i=0;i<len;i++) { hashtable[i]=0; } char *pHashkey=pString; //第一遍遍曆字串,求出每個字元出現的次數 while((*pHashkey)!='\0') { hashtable[(*(pHashkey++))%len]++; } pHashkey=pString; //第二遍遍曆字串,求出第一個只出現一次的字元,每次都是按照字串的順序遍曆 while((*pHashkey)!='\0') { if(hashtable[(*pHashkey)%len]==1) return *pHashkey; pHashkey++; } return '\0';}
上述思想錯誤,因為ASCII%len結果相等,但是ASCII可能不相等。比如字串為“abacdeffk”,那麼第一個只出現一次的字元不是b,而是c。這是因為b跟k對len求hash值結果相同。