面試題50:字符串中第一個只出現一次的字符
一、題目描述
(1)在字符串中找出第一個只出現一次的字符。
如輸入"abaccdeff",則輸出’b’。
(2)字符流中第一個只出現一次的字符
請實現一個函數,用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是’g’。當從該字符流中讀出前六個字符"google"時,第一個只出現一次的字符是’l’
二、問題分析
問題(1):
可以看出來,我們需要記錄字符出現的次數,這個時候很容易聯想到hash表
由於字符(char)是長度爲8位的數據類型,共有256中可能,可以利用字符的ASCII和字符出現的次數湊成 鍵值對。考慮是數字的形式,我們採用數組。
創建以數組爲數據結構的哈希表,鍵值key爲字符的ASCII值,值value爲出現次數。第一遍掃描:對每個掃描到的字符的次數加一;第二遍掃描:對每個掃描到的字符通過哈希表查詢次數,第一個次數爲1的字符即爲符合要求的輸出。
問題(2)
字符只能一個一個從字符流中讀出來,很容易要定義一個容器來保存字符以及其在字符流中的位置。(我們接觸過數據流的習題劍指Offer對答如流系列 - 數據流中的中位數)
同樣,這個數據容器可以用哈希表來實現,以字符的ASCII碼作爲哈希表的鍵值key,字符對應的位置作爲哈希表的值value。
- 開始時,哈希表的值都初始化爲-1,當讀取到某個字符時,將位置存入value中
- 如果之前讀取過該字符(即value>=0),將value賦值爲-2,代表重複出現過。
- 最後對哈希表遍歷,在value>=0的鍵值對中找到最小的value,該value即爲第一個只出現一次的字符,ASCII碼爲key的字符即爲所求字符。
小總結
結合 前面見到的習題,希望你能有這個意識:數據流、字符流等,需要定義數據容器來保存記錄。並能流和串的區別:
- 串:字符串已經保存下來了,能夠讀取遍歷,因此在字符串中第一個只出現一次的字符中,只需要存下每個字符出現的個數,然後直接在字符串中遍歷;
- 流:字符流沒有存下來,無法進行遍歷,因此在本題中,只能在數據容器哈希表中遍歷,而且哈希表中存放的是對應字符的位置,而不是個數。
在腦海中對 字符與ASCII碼的轉化,以及 字符形式的數字轉和整型數字間的轉化 有個比較清晰的認識
//字符轉化爲ASCII碼
char ch_a = 'a';
int code_a = (int)ch_a; // =ASCII碼97
//ASCII碼轉化爲字符
char copyCh_a = (char) code_a; // =ASCII碼97對應的字符'a'
//字符形式數字轉化爲整型
char c1 = '2';
int n1 = c1-'0'; //=2, 由'2'和'1'的ASCII碼相減得到
//數字轉化爲字符形式
char copyC1 = (char)(n1+'0'); //='2' ,由'0'的ASCII碼加2得到'2'的ASCII碼
三、問題解答
問題(1)
public char firstNotRepeatingChar(String str) {
if(str==null) {
return '\0';
}
int[] repetitions = new int[256];
Arrays.fill(repetitions, 0);
for(int i=0;i<str.length();i++) {
int loc= str.charAt(i);
repetitions[loc]+=1;
}
for(int i=0;i<str.length();i++) {
int loc= str.charAt(i);
if(repetitions[loc]==1)
return (char)loc;
}
return '\0';
}
問題(2)
public class FirstCharacterInStream {
private int index;
private int[] occurence;
public FirstCharacterInStream() { //在構造函數中初始化成員變量
index=0;
occurence = new int[256];
Arrays.fill(occurence, -1);
}
public void insert(char ch) {
if(occurence[(int)ch]==-1) {
// 第一次出現
occurence[(int)ch]=index;
} else if(occurence[(int)ch]>=0) {
// 已經出現過了
occurence[(int)ch]=-2;
}
index++;
}
public char getFirst() {
int minIndex=Integer.MAX_VALUE; //最大的integer
char ch='#';
for(int i=0;i<256;i++) {
if(occurence[i]>=0 && occurence[i]<minIndex) {
ch = (char) i;
minIndex=occurence[i];
}
}
return ch;
}
}