1. 程式人生 > 其它 >242. 有效的字母異位詞

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。