劍指 Offer 50. 第一個只出現一次的字元
阿新 • • 發佈:2020-07-27
題目描述
我的題解
(方法三應用更廣泛;方法一雖有限制,但很好用,此題中該方法效率也最高)
方法一:(適用於範圍確定的)
思路分析
- 該字串只包含小寫字母,即字元種類最多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 ' ';
}