Given an array of strings, group anagrams together.
For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"]
,
Return:
[ ["ate", "eat","tea"], ["nat","tan"], ["bat"] ]
Note: All inputs will be in lower-case.
这道题的意思是给定一个字符串数组,然后将相同字母组成的字符串放在一个List里面,最后返回结果。
第一次我的想法是,用数组res纪录每个List<String>中的String的长度,然后遍历数组,先对比已经记录的res数组中的数,如果相同,找到对应List中的String,然后对比这个String和strs[i],但是提交超时。
public class Solution { public List<List<String>> groupAnagrams(String[] strs) { List<List<String>> result = new ArrayList<List<String>>(); int len = strs.length; int[] res = new int[len]; int ans = 0, flag = 0; for (int i = 0; i < len; i++) { flag = 0; for (int j = 0; j < ans; j++) { if (strs[i].length() == res[j]) { if (equal(result.get(j).get(0), strs[i])) { result.get(j).add(strs[i]); flag = 1; break; } } } if (flag == 1) continue; List<String> l1 = new ArrayList<String>(); l1.add(strs[i]); result.add(l1); res[ans] = strs[i].length(); ans++; } return result; } public boolean equal(String str1, String str2) { int len = str1.length(); int[] ans = new int[len]; char[] Str1 = str1.toCharArray(); char[] Str2 = str2.toCharArray(); int flag = 0; for (int i = 0; i < len; i++) { flag = 0; char ch = Str1[i]; for (int j = 0; j < len; j++) { if (ch == Str2[j]) { if (ans[j] == 0) { ans[j] = 1; flag = 1; break; } } } if (flag == 0) return false; } return true; } }
-------------- > 然后修改了res数组,将它改成了纪录每一个List中的String的每一个字母相加得到的数字。但是仍然超时,超时的字符串总共有10000个。
-------------- > 之后修改了res数组,将它改成一个hashMap<Integer,List<Integer>>记录的还是上述内容,ac了,但是时间还是比较长。
代码如下
public class Solution { public List<List<String>> groupAnagrams(String[] strs) { List<List<String>> result = new ArrayList<List<String>>(); Map<Integer,List<Integer>> sum = new HashMap<Integer,List<Integer>>(); int len = strs.length; int flag = 0,len_str = 0,res_pos ,ans = 0; for (int i = 0; i < len; i++) { flag = 0; len_str = 0; for( int j =0;j<strs[i].length();j++) len_str += strs[i].charAt(j); if( sum.containsKey(len_str) ){ List<Integer> l1 = sum.get(len_str); for( int pos = 0;pos<l1.size();pos++){ res_pos = l1.get(pos); if (equal(result.get(res_pos).get(0), strs[i])) { result.get(res_pos).add(strs[i]); flag = 1; break; } } } if (flag == 1) continue; List<String> l1 = new ArrayList<String>(); l1.add(strs[i]); result.add(l1); int num = 0; for( int j = 0;j<strs[i].length();j++){ num += (int)strs[i].charAt(j); } if( sum.containsKey(num)){ List<Integer> l2 = sum.get(num); l2.add(ans); }else{ List<Integer> l2 = new ArrayList<Integer>(); l2.add(ans); sum.put(num,l2); } ans++; } return result; } public boolean equal(String str1, String str2) { int len = str1.length(); if( len != str2.length()) return false; char[] Str1 = str1.toCharArray(); char[] Str2 = str2.toCharArray(); Arrays.sort(Str1); Arrays.sort(Str2); for( int i = 0; i<len;i++){ if( Str1[i] != Str2[i]) return false; } return true; } }
然后在这里发现一个细节:
对于判断两个字符串是否由相同数字组合的时候,第一次写的实际上要比第二次的快不少(虽然第一感觉应该是第二种快一些,因为第一种的最差情况要到n平方的时间复杂度)。
------- >然后发现这里特别慢的原因是hashmap<String,List<Integer>>这里需要建立很多次的List,但是result中又有很多的List<String>其实两者的数量是一样的,所以发现其实可以修改,不用纪录每个字符串相加的和,把每一个字符串(转换成char[]再转回去)排序就可以了,这次酒很快乐,并且代码也少了很多。
public class Solution { public List<List<String>> groupAnagrams(String[] strs) { List<List<String>> result = new ArrayList<List<String>>(); Map<String,List<String>> map = new HashMap<String,List<String>>(); int len = strs.length; for( String s : strs){ char[] ss = s.toCharArray(); Arrays.sort(ss); String sort = new String(ss); if( map.containsKey(sort) ){ map.get(sort).add(s); }else{ List<String> s2 = new ArrayList<String>(); s2.add(s); map.put(sort, s2); result.add(s2); } } return result; } }