给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:[["bat"],["nat","tan"],["ate","eat","tea"]]
解释:
- 在 strs 中没有字符串可以通过重新排列来形成
"bat"。 - 字符串
"nat"和"tan"是字母异位词,因为它们可以重新排列以形成彼此。 - 字符串
"ate","eat"和"tea"是字母异位词,因为它们可以重新排列以形成彼此。
示例 2:
输入: strs = [""]
输出:[[""]]
示例 3:
输入: strs = ["a"]
输出:[["a"]]
提示:
1 <= strs.length <= 1040 <= strs[i].length <= 100strs[i]仅包含小写字母
java
public List<List<String>> groupAnagrams(String[] strs) {
// 创建一个空字典
Map<String, List<String>> map = new HashMap<>();
// 遍历每个单词
for (String s : strs) {
// 第一步:把单词拆成字符数组
// "eat" → ['e','a','t']
char[] chars = s.toCharArray();
// 第二步:对字符排序
// ['e','a','t'] → ['a','e','t']
Arrays.sort(chars);
// 第三步:重新拼成字符串,作为key
// ['a','e','t'] → "aet"
String key = new String(chars);
// 第四步:把原单词放入对应的分组
// 如果字典里没有"aet"这个key,就新建一个空列表
// 如果已经有了,就直接往里加
map.computeIfAbsent(key, k -> new ArrayList<>()).add(s);
}
// 把字典里所有的value(每一组列表)收集起来返回
return new ArrayList<>(map.values());
}
1 List ------ 有序的"列表/数组"
可以把 List 理解成一个可以自由伸缩的数组。
普通数组长度固定:
String[] arr = new String[3]; // 只能放3个,满了就不能加了
List 长度可变:
List<String> list = new ArrayList<>();
list.add("eat"); // ["eat"]
list.add("tea"); // ["eat", "tea"]
list.add("ate"); // ["eat", "tea", "ate"]
List<String> 里的 <String> 表示这个列表只装字符串。
List<List<String>> 就是列表里面装列表,比如:
\["eat", "tea", "ate"\], // 第一组 \["tan", "nat"\], // 第二组 \["bat"\] // 第三组
2 Map ------ "字典/键值对"
Map 就像一本字典,每个"词(key)"对应一个"解释(value)"。
key → value
"aet" → ["eat", "tea", "ate"]
"ant" → ["tan", "nat"]
"abt" → ["bat"]
Map<String, List<String>> map = new HashMap<>();
// 存入数据
map.put("aet", someList);
// 取出数据
map.get("aet"); // 返回 ["eat", "tea", "ate"]
Map<String, List<String>> 表示:
-
key 是 String(排序后的字符串)
-
value 是 List<String>(同一组的单词列表)
3 Map 和 HashMap 的区别
一句话总结
-
Map 是"规范/标准"(接口)
-
HashMap 是"具体实现"(实现类)
生活类比
▎ Map 就像"交通工具"这个概念
▎ HashMap 就像"汽车",是交通工具的一种具体实现
交通工具(Map 接口)
├── 汽车(HashMap) ← 最常用,速度快
├── 火车(TreeMap) ← 会自动排序
└── 自行车(LinkedHashMap) ← 保持插入顺序
接口 vs 实现类
Map 是接口,只定义了"能做什么",但不管"怎么做":
// Map 接口规定了这些方法必须有:
put(key, value) // 存数据
get(key) // 取数据
remove(key) // 删数据
containsKey(key) // 判断key是否存在
HashMap 是实现类,负责具体实现这些方法:
// HashMap 用"哈希表"这种数据结构来实现上面所有方法
为什么要这样写?
// 推荐写法:左边用接口,右边用实现类
Map<String, List<String>> map = new HashMap<>();
// 不推荐:左右都用实现类
HashMap<String, List<String>> map = new HashMap<>();
推荐左边写 Map 的好处:
将来想换一种实现,只改一处地方就够了:
// 想改成有序的?只改右边一个词
Map<String, List<String>> map = new TreeMap<>();
// 想改成保持插入顺序的?
Map<String, List<String>> map = new LinkedHashMap<>();
// 其他用到 map 的代码,一行都不用改!
如果左边写 HashMap,换实现时就要改很多地方。