題目:在字符串中找出第一個只出現一次的字符。如輸入“abaccdeff”,則輸出‘b’。
方法1:
看到這個題目,最直觀的想法就是就是遍歷法,也就是從頭開始取字符串中的一個字符,將其與其后的所有字符比較,如果有相同的字符,那么就證明它不是只出現一次的字符。當第一次出現遍歷完其后字符並且沒有重復時,表明這個字符就是“第一個只出現一次的字符”。如果字符串有n個字符,每個字符可能與后面的O(n)個字符相比較,因此這種思路的時間復雜度是O(n2)。
方法2:
題目中要求第一個只出現一次的字符,那么就跟字符出現的次數有關。我們考慮如何統計字符出現的次數,然后找出第一個次數為1的那個字符。這里我們需要一個數據容器來保存字符出現次數,並且能夠通過字符找出其相對應的次數。哈希表就是一種常用用的容器。
我們可以定義哈希表的鍵值(Key)是字符的ASCII值,而值(Value)是該字符出現的次數。同時我們需要掃描兩次字符串,第一次掃描字符串時,每掃描到一個字符就在哈希表的對應項中把次數加1。接下來第二次掃描的時候,沒掃描到一個字符就能在哈希表中得到該字符出現的次數。找出第一個Value為1的那個key就是我們需要找到那個字符。
方法1和方法2的代碼實現

#include<iostream> #include<stdlib.h> using namespace std; //O(n^n)的時間復雜度 char FirstNotRepeatingChar2(char *pString) { //如果是空指針,返回\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) { //如果是空指針,返回\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。代碼實現如下:

char FirstNotRepeatingChar3(char *pString) { //如果是空指針,返回\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值結果相同。