leetcode刷题记录-1002查找常用字符[java,数组]*

it2022-05-05  99

题目

给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。

你可以按任意顺序返回答案。

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/find-common-characters 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的代码

很惭愧,这道题以我目前对java的了解程度没能做出来。我能够想到的方法非常非常负责,我认为一定不能这么干,于是去看了题解,发现题解使用了Map。然而我对Map近乎一无所知,于是简单学习了一下Map学习笔记 下面还是看被人的代码吧。

别人的代码

class Solution { public List<String> commonChars(String[] A) { List<String> result = new ArrayList<>(); // 数组为空或者长度小于2,直接返回空结果 if(A == null || A.length < 2){ return result; } // 使用Map统计每个字符串中字符出现的次数,并把Map结果放入到List中 List<Map<Character, Integer>> list = new ArrayList<>(); for (String a : A) { Map<Character, Integer> map = new HashMap<>(); for (char c : a.toCharArray()) { if (map.containsKey(c)) { map.put(c, map.get(c) + 1); } else { map.put(c, 1); } } list.add(map); } // 获取所有Map中key的交集(相当于获取每个字符串中都出现的字符) Set<Character> retainSet = list.get(0).keySet(); for (int i = 1; i < list.size(); i++) { retainSet.retainAll(list.get(i).keySet());//取交集 } // 循环key的交集,并把获取到的次数最小的值为结果 // 比如字符串1中a出现了3次,字符串2出现了3次,字符串3出现了1次,那么这3个集合中重复的a的个数就为1 Iterator<Character> iterator = retainSet.iterator(); while (iterator.hasNext()){ Character current = iterator.next(); int minCount = list.get(0).get(current); for (int i = 1; i < list.size(); i++) { Integer cnt = list.get(i).get(current); if(cnt < minCount){ minCount = cnt; } } 作者:ge-bi-xiao-wang 链接:https://leetcode-cn.com/problems/two-sum/solution/zi-fu-tong-ji-fa-by-ge-bi-xiao-wang/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

小结

代码首先提醒了我,java遍历数组完全可以用String a:A,这种写法用List存储不确定长度的结果用Map进行技术(相当于使用Hash定位存储位置用Set找到共有的字符用交集中字符的最小出现次数作为重复部分

但是提交后时间复杂度表现非常差,还是看看官方快速解题的代码

官方更优解

class Solution { public List<String> commonChars(String[] A) { // 入参检查 if(A == null || A.length == 0 || A.length == 1) { return null; } // 记录每个字符出现的次数(字符的ASCII码-97的值做数组下标) int[] hash = new int[26]; // 是否第一次维护hash数组 boolean firstFlag = true; // 遍历字符串 for (String word : A) { // 拆分成字符数组 char[] wordChars = word.toCharArray(); // 如果是第一次维护hash数组 if (firstFlag) { // 直接记录每个字符出现的个数 for (char wordChar : wordChars) { hash[wordChar - 97]++; } // 标志置为否 firstFlag = false; // 如果不是第一次维护,即hash数组中有值时 }else { // 新建临时数组tmpHash来记录当前字符数组每个字符出现的次数 int[] tmpHash = new int[26]; for (char wordChar : wordChars) { tmpHash[wordChar - 97]++; } // 维护hash数组 for(int i = 0; i < hash.length; ++i) { // 比较hash数组和tmpHash数组 // hash记录每次每个字符出现的最小次数 if(hash[i] > tmpHash[i]) { hash[i] = tmpHash[i]; } } } } // 组装返回结果 List<String> res = new ArrayList<>(); for(int i = 0; i < hash.length; ++i) { if(hash[i] != 0) { String tmp = String.valueOf((char)(i + 97)); for(int j = 0; j < hash[i]; ++j) { res.add(tmp); } } } return res; } } 入参检查!!!!!很关键!!!!!要鲁棒!!!!最优解的思路,即转换成ASCII来用int值做键,这一点我是想到了,但是计数的时候我的思路出现了混乱。因为最开始我是准备所有的字符串都用同一个int数组,然后不断累积出现次数,这样我就发现,假设输入为3个字符串,重复字符a出现的次数分别为3,2,1,则按照我的方法会输出2,但其实应该输出1。于是我的思路到此截止。于是我的思路的郁结点在于,没有意识到,对于求最小公共部分,始终保留最小的那个数就可以了。

最新回复(0)