「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。
题目:给定一个字符串,将字符串中字母异位词进行分组,可以按任意顺序分组。所谓的字母异位词,是指字符串顺序存在变化但字符串的组成相同,并且字符串中每个字母只使用一次。
解题思路
本题的关键是理解何为字母异位词,实际上字母异位词的关键是所有词按照字典序排序都是相同的,理解了这一点则可以轻松解决,可以遍历字符串中所有字符串,字符串转为字符数组,之后将每个字符进行字典序排序作为key,如果两个字符的key相同,则必定属于字符异位词,此时如何存储呢?
既然已经提到了key,那Java中一个简单的数据结构Map可以轻松解决,将每个字符的字典序作为key,value是一个ArrayList,之后如果存在字符的排序在此Map,则判定为字母异位词,将其加入ArrayList中即可,将Map中的值取出来保存至一个新的ArrayList中即可,代码如下:
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, ArrayList<String>> map = new HashMap<>();
for(String s:strs){
char[] ch = s.toCharArray();
Arrays.sort(ch);
String key = Arrays.toString(ch);
if(!map.containsKey(key)){
map.put(key, new ArrayList<String>());
}
map.get(key).add(s);
}
return new ArrayList<>(map.values());
}
该方法的时间复杂度为,空间复杂度取决于实际情况。
计数法
另一种方法和上述方式类似,都是将最终的值保存在map中,所不同的是两种方法存放的键的构成不同,如果两个字符串是字母异位词,那么其构成必然相同,例如对于ahe和eha,其都是由一个a一个h和一个e构成的,此时只需将a1e1h1作为键即可,取得此键之后后面操作就和上面方法类似,如何保证按既定顺序获得这些键是一个问题。
解决方法就是我们可以新建一个长度为26位的数组,因为可能出现的字符只有26个,这个数组中存放的就是每个字符出现的次数,之后遍历数组,取出数组内容即可,代码如下:
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, ArrayList<String>> map = new HashMap<>();
for(String s:strs){
int[] ints = new int[26];
for(int i=0;i<s.length();i++){
ints[s.charAt(i)-'a']++;
}
StringBuilder sb = new StringBuilder();
for(int i=0;i<26;i++){
if(ints[i]!=0){
sb.append((char)'a'+i);
sb.append(ints[i]);
}
}
if(!map.containsKey(sb.toString())){
map.put(sb.toString(), new ArrayList<String>());
}
map.get(sb.toString()).add(s);
}
return new ArrayList<>(map.values());
}