题目:Given an array of strings, group anagrams together.For example, given: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”],
Return: [ [“ate”, “eat”,”tea”], [“nat”,”tan”], [“bat”] ]
思路1,使用前面的题目来判断两个字符串是否为anagrams,这样有两种做法,第一个是循环嵌套,判断字符串间关系,并把已经识别过的字符串记录下来,以免重复判断,代码入下:
public static List<List> groupAnagrams(String[] strs) {
List<List> res = new ArrayList<List>();
//存储已经识别过的字符串
Set used = new HashSet<>();
for(int i=0; iif(used.contains(i))
continue;
List ana = new ArrayList<>();
used.add(i);
ana.add(strs[i]);
for(int j=i+1; jif(used.contains(j))
continue;
if(isAnagram1(strs[i], strs[j])){
ana.add(strs[j]);
used.add(j);
}
}
res.add(ana);
}
return res;
}
另外一个方法就是,使用hashMap来存储识别过得字符串,然后遍历,对数组中的每一个字符串都使用hashMap的键值进行匹配,这样的缺点是非常耗时。
public static ListString>> groupAnagrams2(String[] strs) {
ListString>> res = new ArrayListString>>();
Map<String, List<String>> used = new HashMap<>();
for(int i=0; ifalse;
for(String ss : used.keySet()){
if(isAnagram1(strs[i], ss)){
List<String> aa = used.get(ss);
aa.add(strs[i]);
used.put(ss, aa);
flag = true;
break;
}
}
if(flag == false){
List<String> aa = new ArrayList<>();
aa.add(strs[i]);
used.put(strs[i], aa);
}
}
for(String ss:used.keySet())
res.add(used.get(ss));
return res;
}
以上两种方法中的isAnagram1都是之前一个题目中写的效率最高函数。如下。但是发现最终提交结果时都显示超时。说明一开始这种借用之前题目成果的办法并不适用。痛定思痛,接下来想一想有什么改进办法。
public static boolean isAnagram1(String s, String t) {
if(s.length() != t.length())
return false;
int [] tmp = new int[26];
for(char c : s.toCharArray())
tmp[c-'a'] ++;
for(char c:t.toCharArray())
tmp[c-'a'] --;
for(int a:tmp)
if(a!=0)
return false;
return true;
}
首先按照方法二进行改进,对每个字符串进行遍历的时候,先对其进行排序然后将其作为键值保存到hashMap中,这样就可以省去麻烦的判断过程,而直接使用hashMap.containsKey方法来达到判断的效果。节省了很多循环的时间。但这样的改进带来的提升有限,只击败了15%的用户
public ListString>> groupAnagrams3(String[] strs) {
if(strs==null || strs.length == 0){
return new ArrayListString>>();
}
HashMap<String, List<String>> map = new HashMap<String, List<String>>();
//Arrays.sort(strs);
for (String s:strs) {
char[] ca = s.toCharArray();
Arrays.sort(ca);
String keyStr = String.valueOf(ca);
if(!map.containsKey(keyStr))
map.put(keyStr, new ArrayList<String>());
map.get(keyStr).add(s);
}
for(String key: map.keySet()) {
Collections.sort(map.get(key));
}
return new ArrayListString>>(map.values());
}
最后,还有一种极为巧妙的方法,使用26个质数与字母一一对应相乘作为字符串的键值保存到hashMap中。这样就省去了字符串的排序等操作,而且这种方法省去了最后对hashMap遍历生成列表的过程也节省了很多时间。这种方法击败了99%的用户。
public List> groupAnagrams4(String[] strs) {
int[] prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103};//最多10609个z
List> res = new ArrayList<>();
HashMap map = new HashMap<>();
for (String s : strs) {
int key = 1;
for (char c : s.toCharArray()) {
key *= prime[c - 'a'];
}
List t;
if (map.containsKey(key)) {
t = res.get(map.get(key));
} else {
t = new ArrayList<>();
res.add(t);
map.put(key, res.size() - 1);
}
t.add(s);
}
return res;
}