劍指Offer對答如流系列 - 字符串中第一個只出現一次的字符

面試題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. 開始時,哈希表的值都初始化爲-1,當讀取到某個字符時,將位置存入value中
  2. 如果之前讀取過該字符(即value>=0),將value賦值爲-2,代表重複出現過。
  3. 最後對哈希表遍歷,在value>=0的鍵值對中找到最小的value,該value即爲第一個只出現一次的字符,ASCII碼爲key的字符即爲所求字符。

小總結

結合 前面見到的習題,希望你能有這個意識:數據流、字符流等,需要定義數據容器來保存記錄。並能流和串的區別:

  1. 串:字符串已經保存下來了,能夠讀取遍歷,因此在字符串中第一個只出現一次的字符中,只需要存下每個字符出現的個數,然後直接在字符串中遍歷;
  2. 流:字符流沒有存下來,無法進行遍歷,因此在本題中,只能在數據容器哈希表中遍歷,而且哈希表中存放的是對應字符的位置,而不是個數。

在腦海中對 字符與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;
    }
}
發佈了194 篇原創文章 · 獲贊 3472 · 訪問量 53萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章