题目:
Given an array of strings, group anagrams together.
Example:
Input:["eat", "tea", "tan", "ate", "nat", "bat"],Output:[ ["ate","eat","tea"], ["nat","tan"], ["bat"] ]Note:
- All inputs will be in lowercase.
- The order of your output does not matter.
这道题就是简单地把一个array of strings里的anagram给group到一个list里。看到anagram想到的第一个方法就是排序,本来以为会有更好的解法,没想到最naive的排序法应该算是最好的解法了吧。看了solution以后才想到,anagram的另一种解法是count,差点给忘了,本质上感觉这俩都一样。以后见着anagram就可以往这两个思路上面靠。
1. sorting,刚开始还想岔了,后来才发现可以直接建一个map,key是sorted后的string,value是排序后是这个key的string的a list of strings,直接遍历一通把它们一个个塞进去就好了。这里学到了java对string排序的方法。时间复杂度应该是O(nklogk),k是单个单词的长度,n是数组的长度。空间复杂度O(nk)。
Runtime: 6 ms, faster than 98.20% of Java online submissions for Group Anagrams.
Memory Usage: 42.2 MB, less than 91.45% of Java online submissions for Group Anagrams.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (int i = 0; i < strs.length; i++) { char[] chars = strs[i].toCharArray(); Arrays.sort(chars); String sorted = new String(chars); if (!map.containsKey(sorted)) { map.put(sorted, new ArrayList<>()); } map.get(sorted).add(strs[i]); } return new ArrayList<>(map.values()); } }2026.10.20 - 复习一下string和char array之间的转换和数组的sort语法。
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> groups = new HashMap<>(); for (String str : strs) { char[] chars = str.toCharArray(); Arrays.sort(chars); String sorted = new String(chars); groups.computeIfAbsent(sorted, k -> new ArrayList<>()).add(str); } return new ArrayList<>(groups.values()); } }2. counting,本质和sorting差不多,就是利用了anagram每个字母出现的次数相同这个规律。代码写起来也跟上面差不多,就是要count一下每个string里每个字母出现的次数,会比较麻烦,而且count次数用的这个array还不能直接用作hashmap的key,大概是因为这是个mutable object吧(有了gpt老师以后,知道了是因为Java 数组默认比较的是引用,而不是数组里的内容),所以代码会复杂一点。但是这个count的时间复杂度只需要对单词长度进行遍历就好,所以整体时间复杂度比sorting优秀,是O(nk),空间复杂度也一样是O(nk)。(诶,不过不知道为啥lc上算出来的运行时间咋多了这么多)
Runtime: 18 ms, faster than 30.36% of Java online submissions for Group Anagrams.
Memory Usage: 44 MB, less than 43.36% of Java online submissions for Group Anagrams.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (int i = 0; i < strs.length; i++) { int[] count = new int[26]; for (char c : strs[i].toCharArray()) { count[c - 'a']++; } String countStr = Arrays.toString(count); if (!map.containsKey(countStr)) { map.put(countStr, new ArrayList<>()); } map.get(countStr).add(strs[i]); } return new ArrayList<>(map.values()); } }2026.10.20 - 这次第一个想到的就是计数,但是折腾这些map啥的花了好久。以及还是不记得需要把频率变成string才行。顺便复习一下computeIfAbsent的用法。
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> groups = new HashMap<>(); for (String str : strs) { String count = countFreq(str); groups.computeIfAbsent(count, k -> new ArrayList<>()).add(str); } return new ArrayList<>(groups.values()); } private String countFreq(String str) { int[] freq = new int[26]; for (char c : str.toCharArray()) { freq[c - 'a']++; } StringBuilder sb = new StringBuilder(); for (int i : freq) { sb.append("#").append(i); } return sb.toString(); } }(才发现原来去年做过这道题……当时用的C++代码就不贴了,复制一下当时随心写的,就可以删去年那篇不走心的了:
普通地遍历整个数组,统计每个词中每个字符出现的频率,把频率变成一个string用来作为hashmap的key,把生成相同的频率string的词放在这个key的value vector里,最后取所有的vector作为答案。
本来以为上面的count计数法会比排序快,因为排序的复杂度更高,没想到出来的结果却是排序超级快但是计数超级慢,猜测可能是因为string operations速度比较慢?)