字母异位分组力扣--49
目录
题目
思路
代码
computeIfAbsent()
题目
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
思路
理解:给你一个字符串数组,把里面的字母异位放在一起
既然是字母异位,那么将他们排序后,应该是相同的,所以当且仅当两个字符串排序后一样,这两个字符串才能分到同一组。
代码
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
// 创建一个HashMap,用于存储字母异位词分组的结果
// 键是经过排序后的字符串,值是由对应的字母异位词组成的List<String>
Map<String, List<String>> m = new HashMap<>();
// 遍历输入的字符串数组strs
for (String str : strs) {
// 将当前字符串str转换为字符数组,方便后续进行排序操作
char[] s = str.toCharArray();
// 对字符数组进行排序,经过排序后,字母异位词会具有相同的字符顺序
Arrays.sort(s);
// 使用computeIfAbsent方法来处理键值对的添加逻辑
// 如果以排序后的字符串(new String(s))作为键,在Map中不存在对应的键值对
// 那么就通过后面的lambda表达式创建一个新的空的ArrayList<>()作为值,添加到Map中
// 如果键已经存在,就返回已存在的对应的值(也就是对应的字母异位词列表)
m.computeIfAbsent(new String(s), k -> new ArrayList<>()).add(str);
}
// 返回Map中所有的值(也就是各个分组好的字母异位词列表)组成的新的ArrayList
return new ArrayList<>(m.values());
}
}
computeIfAbsent()
computeIfAbsent
方法是Map
接口提供的一个很方便的方法,它接收两个参数:第一个参数是要检查是否存在的键(在这里就是排序后的字符串,通过new String(s)
创建,因为Arrays.sort
操作的是字符数组,需要转换回字符串形式来作为键);第二个参数是一个Function
接口实现(这里使用了 lambda 表达式k -> new ArrayList<>()
),这个实现的作用是当键不存在时,用来生成对应的值(也就是创建一个新的空的ArrayList
来存放属于同一组的字母异位词)
对 hashMap 中指定 key 的值进行重新计算,如果不存在这个 key,则添加到 hashMap 中。
语法:
hashmap.computeIfAbsent(K key, Function remappingFunction)
注:hashmap 是 HashMap 类的一个对象。
- key - 键
- remappingFunction - 重新映射函数,用于重新计算值
如果 key 对应的 value 不存在,则使用获取 remappingFunction 重新计算后的值,并保存为该 key 的 value,否则返回 value。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
// 使用Java 8的Stream API来处理字符串数组strs,最后将处理结果转换为ArrayList返回
return new ArrayList<>(
// 首先将字符串数组strs转换为一个Stream流,这样就能利用流的各种操作来处理数据
Arrays.stream(strs)
// 使用collect方法进行收集操作,这里主要利用了Collectors.groupingBy来进行分组
.collect(Collectors.groupingBy(str -> {
// 以下是定义分组的依据,也就是分组的键的生成逻辑
// 先将当前字符串str转换为字符数组,目的是为了能够对字符进行排序操作
char[] array = str.toCharArray();
// 利用Arrays.sort方法对字符数组进行排序,使得字母异位词在排序后会具有相同的字符顺序
Arrays.sort(array);
// 将排序后的字符数组再转换回字符串,这个字符串就作为分组的依据(类似于SQL里的group by操作中的分组依据)
return new String(array);
}))
// 取出分组后的结果中所有的值(也就是各个分组好的字母异位词列表),因为collect操作返回的是一个Map,键是分组依据(排序后的字符串),值是对应的字母异位词列表
.values()
);
}
}
Java8 Stream 之sorted方法 排序讲解_stream().sorted-CSDN博客
对每个字符串计数得到该字符串的计数数组,对于计数数组相同的字符串,就互为异位词。
因为数组类型没有重写 hashcode() 和 equals() 方法,因此不能直接作为 HashMap 的 Key 进行聚合,那么我们就 把这个数组手动编码变成字符串就行了。
比如将 [b,a,a,a,b,c] 编码成 a3b2c1,使用编码后的字符串作为 HashMap 的 Key 进行聚合。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
return new ArrayList<>(Arrays.stream(strs)
.collect(Collectors.groupingBy(str -> {
int[] counter = new int[26];
for (int i = 0; i < str.length(); i++) {
counter[str.charAt(i) - 'a']++;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 26; i++) {
// 这里的 if 是可省略的,但是加上 if 以后,生成的 sb 更短,后续 groupingBy 会更快。
if (counter[i] != 0) {
sb.append((char) ('a' + i));
sb.append(counter[i]);
}
}
return sb.toString();
})).values());
}
}
设 n 是数组长度,k 是字符串最大长度。