群组错位词。题意是给一个数组,数组里面的元素是字符串,请将input根据错位词的原则分组输出。例子,
Example:
Input:["eat", "tea", "tan", "ate", "nat", "bat"]
, Output: [ ["ate","eat","tea"], ["nat","tan"], ["bat"] ]
做这个题之前,需要做如下几个题,对anagram的概念有所了解。
242. Valid Anagram
383. Ransom Note
387. First Unique Character in a String
此题比较粗暴的解法是把input里面所有的单词都按照字母排序,形成一个新的单词。比如"eat"排序后会成为"aet",然后以"aet"为key,"eat"为value加入hashmap。遍历完input之后,输出hashmap所有的value即可。
时间O(nlogn) - sort
空间O(n) - hashmap
1 /** 2 * @param {string[]} strs 3 * @return {string[][]} 4 */ 5 var groupAnagrams = function (strs) { 6 const map = {}; 7 for (let str of strs) { 8 const key = [...str].sort().join(''); 9 if (!map[key]) { 10 map[key] = []; 11 } 12 map[key].push(str); 13 } 14 return Object.values(map); 15 };
但是如上不是最优解,最优解还是要通过counting sort的思路来做。对于每个单词,需要创建一个长度为26的数组(题目说了只有小写)来存这个单词里面每个字母都分别出现过几次。这样每个单词最后形成的数组会长得像这样,
[ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ][ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ][ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 ]
然后把这个数组稍微变化一下,做成一个类似这样的string
1#0#0#0#1#0#0#0#0#0#0#0#0#0#0#0#0#0#0#1#0#0#0#0#0#0
把这个string当做hashmap的key。这样每个扫描过的单词都会变成这样,是错位词的单词们的string会长得一样,所以在hashmap中会被存到同一个key里面。最后以数组形式输出hashmap里面所有的value即可。
时间O(n) - 没有排序
空间O(n)
1 /** 2 * @param {string[]} strs 3 * @return {string[][]} 4 */ 5 var groupAnagrams = function (strs) { 6 const map = new Map(); 7 for (const s of strs) { 8 const letters = Array(26).fill(0); 9 for (const c of s) { 10 letters[c.charCodeAt(0) - 97]++; 11 } 12 console.log(letters); 13 const key = letters.join("#"); 14 console.log(key); 15 let val = []; 16 if (map.has(key)) { 17 val = map.get(key); 18 } 19 val.push(s); 20 map.set(key, val); 21 } 22 23 return Array.from(map.values()); 24 };