[劍指Offer]面試題35:第一個只出現一次的字元

陶程發表於2016-03-19

題目

給定一個字串,求第一個不重複的字元 abbcad -> c

解題思路:

今天中午面試的時候第二題我的思路是從頭開始掃描字串中的每個字元。當訪問到某字元時拿這個字元和後面的每個字元相比較。如果在後面沒有發現重複的字元,則該字元就是隻出現一次的字元。如果字串有n個字元,每個字元可能與後面的O(n)個字串相比較,因此這種思路的時間複雜度為O(n^2)。

這不是最好的做法,更好的做法時間複雜度應該是O(n)。


後來我回去仔細想了下,擴充思維想到能不能借助輔助容器的思路,然後採用Java中的資料容器來存放每個字元出現的次數。
為了解決這個問題,可以定義LinkedHashMap的鍵(key)是字元,而值(value)是該字元出現的次數。

思路:

我們需要從頭開始掃描字串兩次,第一次掃描字串時,每掃描到一個字元就在雜湊表的對應項把次數加1。接下來第二次掃描時,每掃描到一個字元就能從雜湊表中得到該字元出現的次數。這樣第一個只出現一次的字元就是符合要求的輸出。

時間複雜度分析:

第一個for迴圈中在雜湊表中更新一個字元出現的次數的時間複雜度是O(n)。第二個for時間複雜度也是O(n),兩個for迴圈最多執行2n次,總共的時間複雜度是O(n),符合題目的要求。

程式碼實現:

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class Main {

    public static void main(String[] args) {
        System.out.println(get("alibaba"));
        System.out.println(get("taobao"));
        System.out.println(get("aabbccd"));
        System.out.println(get("ddbbdd"));
        System.out.println(get("ahsdkdhask"));
    }

    /**
     * 返回第一個不重複的字元
     * @param s 所求的字串
     * @return  如果有返回該字元,如果不存在不重負的字元,返回null
     */
    public static Character get(String s) {
        // 判斷邊界條件
        if (s == null || s.length() < 1) {
            // 丟擲異常
            throw new IllegalArgumentException("should not be null or empty");
        }
        Map<Character, Integer> map = new LinkedHashMap<Character, Integer>();
        int len = s.length();

        for (int i = 0; i < len; i++) {
            char c = s.charAt(i);
            Integer already = map.get(c);
            already = (already == null) ? 0 : already;
            map.put(s.charAt(i), ++already);
        }

        Set<Map.Entry<Character, Integer>> entries = map.entrySet();
        for (Map.Entry<Character, Integer> entry : entries) {
            if (entry.getValue() == 1) {
                return entry.getKey();
            }
        }
        return null;
    }
}

執行結果正確,如果沒有返回null。

相關文章