LeetCode 力扣 49. 字母異位詞分組

題目描述(中等難度)

給定多個字符串传黄,然后把它們分類址遇。只要字符串所包含的字符完全一樣就算作一類,不考慮順序滋戳。

解法一

最通用的一種解法钻蔑,對于每個字符串啥刻,比較它們的每個字符出現(xiàn)的個數(shù)是否相等,相等的話就把它們放在一個 list 中去咪笑,作為一個類別可帽。最外層寫一個 for 循環(huán)然后一一比較就可以,還可以用一個等大的布爾型數(shù)組來記錄當前字符串是否已經(jīng)加入的了 list 窗怒。比較兩個字符串的字符出現(xiàn)的次數(shù)可以用一個 HashMap映跟,具體看代碼吧。

public List<List<String>> groupAnagrams(String[] strs) {
    List<List<String>> ans = new ArrayList<>();
    boolean[] used = new boolean[strs.length];
    for (int i = 0; i < strs.length; i++) {
        List<String> temp = null;
        if (!used[i]) {
            temp = new ArrayList<String>();
            temp.add(strs[i]);
            //兩兩比較判斷字符串是否符合
            for (int j = i + 1; j < strs.length; j++) {
                if (equals(strs[i], strs[j])) {
                    used[j] = true;
                    temp.add(strs[j]);
                }
            }
        }
        if (temp != null) {
            ans.add(temp);

        }
    }
    return ans;

}

private boolean equals(String string1, String string2) {
    Map<Character, Integer> hash = new HashMap<>();
    //記錄第一個字符串每個字符出現(xiàn)的次數(shù)扬虚,進行累加
    for (int i = 0; i < string1.length(); i++) {
        if (hash.containsKey(string1.charAt(i))) {
            hash.put(string1.charAt(i), hash.get(string1.charAt(i)) + 1);
        } else {
            hash.put(string1.charAt(i), 1);
        }
    }
     //記錄第一個字符串每個字符出現(xiàn)的次數(shù)努隙,將之前的每次減 1
    for (int i = 0; i < string2.length(); i++) {
        if (hash.containsKey(string2.charAt(i))) {
            hash.put(string2.charAt(i), hash.get(string2.charAt(i)) - 1);
        } else {
            return false;
        }
    }
    //判斷每個字符的次數(shù)是不是 0 ,不是的話直接返回 false
    Set<Character> set = hash.keySet();
    for (char c : set) {
        if (hash.get(c) != 0) {
            return false;
        }
    }
    return true;
}

時間復雜度:雖然看起來外層用了兩個 for 循環(huán)辜昵,但是我們通過 used 數(shù)組保證了每個字符串只會訪問 1 次荸镊,所以外層的復雜度是字符串數(shù)組的長度 O(n),判斷兩個字符串相等的函數(shù) equal 函數(shù)堪置,時間復雜度是字符串的最長長度 O(K)躬存。所以總共就是 O(nK)。

空間復雜度:O(NK)舀锨,用來存儲結(jié)果岭洲。

解法一算是比較通用的解法,不管字符串里邊是大寫字母坎匿,小寫字母盾剩,數(shù)字,都可以用這個算法解決碑诉。這道題的話彪腔,題目告訴我們字符串中只有小寫字母,針對這個限制进栽,我們可以再用一些針對性強的算法德挣。

下邊的算法本質(zhì)是,我們只要把一類的字符串用某一種方法唯一的映射到同一個位置就可以快毛。

解法二

參考官方給的解法格嗅。

我們將每個字符串按照字母順序排序,這樣的話就可以把 eat唠帝,tea屯掖,ate 都映射到 aet。其他的類似襟衰。

public List<List<String>> groupAnagrams(String[] strs) {
    HashMap<String, List<String>> hash = new HashMap<>();
    for (int i = 0; i < strs.length; i++) {
        char[] s_arr = strs[i].toCharArray();
        //排序
        Arrays.sort(s_arr);
        //映射到 key
        String key = String.valueOf(s_arr); 
        //添加到對應的類中
        if (hash.containsKey(key)) {
            hash.get(key).add(strs[i]);
        } else {
            List<String> temp = new ArrayList<String>();
            temp.add(strs[i]);
            hash.put(key, temp);
        }

    }
    return new ArrayList<List<String>>(hash.values()); 
}

時間復雜度:排序的話算作 O(K log(K)),最外層的 for 循環(huán)贴铜,所以就是 O(n K log(K))。

空間復雜度:O(NK),用來存儲結(jié)果绍坝。

解法三

參考這里徘意,利用算術基本定理

算術基本定理轩褐,又稱為正整數(shù)的唯一分解定理椎咧,即:每個大于1的自然數(shù),要么本身就是質(zhì)數(shù)把介,要么可以寫為2個以上的質(zhì)數(shù)的勤讽,而且這些質(zhì)因子按大小排列之后,寫法僅有一種方式拗踢。

利用這個脚牍,我們把每個字符串都映射到一個正數(shù)上。

用一個數(shù)組存儲質(zhì)數(shù) prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103}秒拔。

然后每個字符串的字符減去 ' a ' 莫矗,然后取到 prime 中對應的質(zhì)數(shù)飒硅。把它們累乘砂缩。

例如 abc ,就對應 'a' - 'a'三娩, 'b' - 'a'庵芭, 'c' - 'a',即 0, 1, 2雀监,也就是對應素數(shù) 2 3 5双吆,然后相乘 2 * 3 * 5 = 30,就把 "abc" 映射到了 30会前。

public List<List<String>> groupAnagrams(String[] strs) {
    HashMap<Integer, List<String>> hash = new HashMap<>();
    //每個字母對應一個質(zhì)數(shù)
    int[] prime = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103 };
    for (int i = 0; i < strs.length; i++) {
        int key = 1;
        //累乘得到 key
        for (int j = 0; j < strs[i].length(); j++) {
            key *= prime[strs[i].charAt(j) - 'a'];
        } 
        if (hash.containsKey(key)) {
            hash.get(key).add(strs[i]);
        } else {
            List<String> temp = new ArrayList<String>();
            temp.add(strs[i]);
            hash.put(key, temp);
        }

    }
    return new ArrayList<List<String>>(hash.values());
}

時間復雜度:O(n * K)好乐,K 是字符串的最長長度。

空間復雜度:O(NK)瓦宜,用來存儲結(jié)果蔚万。

這個解法時間復雜度,較解法二有提升临庇,但是有一定的局限性反璃,因為求 key 的時候用的是累乘,可能會造成溢出假夺,超出 int 所能表示的數(shù)字淮蜈。

解法四

參考這里,記錄字符串的每個字符出現(xiàn)的次數(shù)從而完成映射已卷。因為有 26 個字母梧田,不好解釋,我們假設只有 5 個字母,來看一下怎么完成映射裁眯。

首先初始化 key = "0#0#0#0#0#"肖方,數(shù)字分別代表 abcde 出現(xiàn)的次數(shù),# 用來分割未状。

這樣的話俯画,"abb" 就映射到了 "1#2#0#0#0"。

"cdc" 就映射到了 "0#0#2#1#0"司草。

"dcc" 就映射到了 "0#0#2#1#0"艰垂。

public List<List<String>> groupAnagrams(String[] strs) {
    HashMap<String, List<String>> hash = new HashMap<>();
    for (int i = 0; i < strs.length; i++) {
        int[] num = new int[26];
        //記錄每個字符的次數(shù)
        for (int j = 0; j < strs[i].length(); j++) {
            num[strs[i].charAt(j) - 'a']++;
        }
        //轉(zhuǎn)成 0#2#2# 類似的形式
        String key = "";
        for (int j = 0; j < num.length; j++) {
            key = key + num[j] + '#';
        }
        if (hash.containsKey(key)) {
            hash.get(key).add(strs[i]);
        } else {
            List<String> temp = new ArrayList<String>();
            temp.add(strs[i]);
            hash.put(key, temp);
        }

    }
    return new ArrayList<List<String>>(hash.values());
}

時間復雜度: O(nK)。

空間復雜度:O(NK)埋虹,用來存儲結(jié)果猜憎。

利用 HashMap 去記錄字符的次數(shù)之前也有遇到過,很常用搔课。解法三中利用質(zhì)數(shù)相乘胰柑,是真的太強了。

更多詳細通俗題解詳見 leetcode.wang 爬泥。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柬讨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子袍啡,更是在濱河造成了極大的恐慌踩官,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡臂容,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門辩越,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人信粮,你說我怎么就攤上這事黔攒。” “怎么了蒋院?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵亏钩,是天一觀的道長。 經(jīng)常有香客問我欺旧,道長姑丑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任辞友,我火速辦了婚禮栅哀,結(jié)果婚禮上震肮,老公的妹妹穿的比我還像新娘。我一直安慰自己留拾,他們只是感情好戳晌,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著痴柔,像睡著了一般沦偎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咳蔚,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天豪嚎,我揣著相機與錄音,去河邊找鬼谈火。 笑死侈询,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的糯耍。 我是一名探鬼主播扔字,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼温技!你這毒婦竟也來了革为?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤荒揣,失蹤者是張志新(化名)和其女友劉穎篷角,沒想到半個月后焊刹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體系任,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年虐块,在試婚紗的時候發(fā)現(xiàn)自己被綠了俩滥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡贺奠,死狀恐怖霜旧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情儡率,我是刑警寧澤挂据,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站儿普,受9級特大地震影響崎逃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜眉孩,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一个绍、第九天 我趴在偏房一處隱蔽的房頂上張望勒葱。 院中可真熱鬧,春花似錦巴柿、人聲如沸凛虽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凯旋。三九已至,卻和暖如春钉迷,著一層夾襖步出監(jiān)牢的瞬間瓦阐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工篷牌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留睡蟋,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓枷颊,卻偏偏與公主長得像戳杀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子夭苗,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 字母異位詞分組 來源:力扣(LeetCode)著作權(quán)歸領扣網(wǎng)絡所有信卡。 題目描述:給定一個符串數(shù)組,將字母異位詞組合...
    腐爛的橘子閱讀 223評論 0 1
  • 2019-03-14 題目描述: 思路1解析 本題可以通過數(shù)學當中的質(zhì)數(shù)的原理進行求解 题造。 質(zhì)數(shù)原理:任何一個和數(shù)...
    高大寬333閱讀 528評論 0 0
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學一百閱讀 3,237評論 0 4
  • 對睡眠質(zhì)量不好的反思 其一我沒有提前說我要睡覺了界赔,室友吵醒我丢习,早睡的時間受到干擾。其二沒購買新耳塞淮悼。其三調(diào)了鬧鈴咐低,...
    有思想的大烏龜閱讀 345評論 7 2
  • 這幾個月一直非常不順,我很沮喪袜腥,有點想死见擦。每次這個時候我會去關注身邊的人,看她們是否有注意到我羹令,能顧及我的情緒鲤屡。就...
    ygmsn閱讀 78評論 0 0