题目
给定仅有小写字母组成的字符串数组 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。于是我的思路到此截止。
- 于是我的思路的郁结点在于,没有意识到,对于求最小公共部分,始终保留最小的那个数就可以了。