1. 程式人生 > 實用技巧 >劍指 Offer 50. 第一個只出現一次的字元

劍指 Offer 50. 第一個只出現一次的字元


本題 題目連結

題目描述


我的題解

(方法三應用更廣泛;方法一雖有限制,但很好用,此題中該方法效率也最高)

方法一:(適用於範圍確定的)

思路分析

  • 該字串只包含小寫字母,即字元種類最多26個
  • 開一個數組yes[26],分別存放字母a-z所出現的次數。
  • 字元c對應的陣列下標索引為為:c-97.
  • 我的程式碼中,為了節約空間,取的是byte型別陣列:
    • 當某個字元出現次數<2,該字元對應的陣列值+1;
    • 否則(即出現次數>=2,不符合題目要找的),不處理該字元對應的陣列值(即不再+1,因為byte型別最大值為127,而題目資料可能出現某個字元出現次數多達50000的情況)。

程式碼如下

    public char firstUniqChar(String s) {
        char[] chars = s.toCharArray();
        byte[] yes = new byte[26];
        for (char c : chars) {
            if (yes[c-97]<2)yes[c-97]++;
        }
        char res = ' ';
        for (char c : chars) {
            if (yes[c-97]==1) {
                res = c;
                break;
            }
        }
        return res;
    }

方法二:雜湊表

方法二的優化 是參考leetcode大佬的題解。大佬leetcode主頁

思路分析

  • 建立一個雜湊表:HashMap<Character, Boolean> dic。
  • 遍歷字串s 中的每個字元 c:
    • 若字元c第一次出現,則向dic中新增鍵值對:dic.put(c, true);
    • 若前面已經出現過,則修改鍵c的鍵值對:dic.put(c, false) 【字元c數量大於1,不符合題目要找的】;

程式碼如下:

    public char firstUniqChar(String s) {
        Map<Character, Boolean> dic = new HashMap<>();
        char[] chars = s.toCharArray();

        for (char c : chars) {  // 遍歷字串
            dic.put(c, !dic.containsKey(c)); // 若dic中不包含鍵 c :則向dic中新增鍵值對 (c, True) ;
                                            // 若包含鍵 c :則修改鍵c的鍵值對為 (c, False)。
        }
        char res = ' ';
        // 再次遍歷字串s,檢視雜湊表中鍵 c對應的value值,找出第一個true
        for (char c : chars) {
            if (dic.get(c)) {
                res = c;
                break;
            }
        }
        return res;
    }

方法三:有序雜湊表

方法三 是參考leetcode大佬的題解。大佬leetcode主頁

思路分析

  • 在雜湊表的基礎上,有序雜湊表中的鍵值對是 按照插入順序排序 的。
  • 故在方法二的基礎上, 對於資料量大的題目,方法三效率更高。
  • 方法二中,第二個for迴圈,遍歷的是字串s;而方法三中第二個for迴圈只需遍歷有序雜湊表即可(因雜湊表是去重的,故減少了迴圈的次數,增加了效率)

程式碼如下

    public char firstUniqChar(String s) {
        Map<Character, Boolean> dic = new LinkedHashMap<>();
        char[] chars = s.toCharArray();

        for (char c : chars) {
            dic.put(c, !dic.containsKey(c)); // 若dic中不包含鍵 c :則向dic中新增鍵值對 (c, True) ;
                                            // 若包含鍵 c :則修改鍵c的鍵值對為 (c, False)。
        }

        for (Map.Entry<Character, Boolean> entry : dic.entrySet()) {
            if (entry.getValue()) return entry.getKey();
        }
        return ' ';
    }