242. 有效的字母異位詞
題目:https://leetcode-cn.com/problems/valid-anagram/
想法:題目中說的是26個小寫字母,那定義一個字典用來統計s中每個字母出現的頻率
C++版本: bool isAnagram(string s, string t){ int dictionary[26] = {0}; for (int i = 0; i < s.size(); i++){ dictionary[s[i] - 'a']++; } for (int j = 0; j < t.size(); j++){ dictionary[t[j]- 'a']--; } for (int k = 0; k < 26; k++){ if (dictionary[k] != 0) return false; } return true; }
程式碼隨想錄:https://programmercarl.com/0242.%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D.html#_242-%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D
我的想法和這個一樣,“程式碼隨想錄”中總結得比較全面,此類演算法屬於“雜湊表”一類
官網:https://leetcode-cn.com/problems/valid-anagram/solution/you-xiao-de-zi-mu-yi-wei-ci-by-leetcode-solution/
方法一:排序
t 是 s 的異位詞等價於「兩個字串排序後相等」。因此我們可以對字串 s 和 t 分別排序,看排序後的字串是否相等即可判斷。此外,如果 s 和 t 的長度不同,t 必然不是 s 的異位詞。
C++版本: bool isAnagram(string s, string t) { if (s.length() != t.length()) {return false; } sort(s.begin(), s.end()); sort(t.begin(), t.end()); return s == t; }
複雜度分析
時間複雜度:O(nlogn),其中 n 為 s 的長度。排序的時間複雜度為 O(nlogn),比較兩個字串是否相等時間複雜度為 O(n),因此總體時間複雜度為O(nlogn+n)=O(nlogn)。
空間複雜度:O(logn)。排序需要 O(logn) 的空間複雜度。注意,在某些語言(比如 Java & JavaScript)中字串是不可變的,因此我們需要額外的 O(n) 的空間來拷貝字串。但是我們忽略這一複雜度分析,因為:
這依賴於語言的細節;
這取決於函式的設計方式,例如,可以將函式引數型別更改為 char[]。
方法二:雜湊表
從另一個角度考慮,t 是 s 的異位詞等價於「兩個字串中字元出現的種類和次數均相等」。由於字串只包含 26 個小寫字母,因此我們可以維護一個長度為 26 的頻次陣列table,先遍歷記錄字串 s 中字元出現的頻次,然後遍歷字串 t,減去table 中對應的頻次,如果出現 table[i]<0,則說明 t 包含一個不在 s 中的額外字元,返回 false 即可。
C++版本: bool isAnagram(string s, string t) { if (s.length() != t.length()) { return false; } vector<int> table(26, 0); for (auto& ch: s) { table[ch - 'a']++; } for (auto& ch: t) { table[ch - 'a']--; if (table[ch - 'a'] < 0) { return false; } } return true; }
對於進階問題,Unicode 是為了解決傳統字元編碼的侷限性而產生的方案,它為每個語言中的字元規定了一個唯一的二進位制編碼。而 Unicode 中可能存在一個字元對應多個位元組的問題,為了讓計算機知道多少位元組表示一個字元,面向傳輸的編碼方式的 UTF−8 和 UTF−16 也隨之誕生逐漸廣泛使用,具體相關的知識讀者可以繼續查閱相關資料拓展視野,這裡不再展開。
回到本題,進階問題的核心點在於「字元是離散未知的」,因此我們用雜湊表維護對應字元的頻次即可。同時讀者需要注意 Unicode 一個字元可能對應多個位元組的問題,不同語言對於字串讀取處理的方式是不同的。
JAVA版本: public boolean isAnagram(String s, String t) { if (s.length() != t.length()) { return false; } Map<Character, Integer> table = new HashMap<Character, Integer>(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); table.put(ch, table.getOrDefault(ch, 0) + 1); } for (int i = 0; i < t.length(); i++) { char ch = t.charAt(i); table.put(ch, table.getOrDefault(ch, 0) - 1); if (table.get(ch) < 0) { return false; } } return true; }
複雜度分析
-
時間複雜度:O(n),其中n為s的長度。
-
空間複雜度:O(S),其中S為字符集大小,此處S=26。