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

题目

给定仅有小写字母组成的字符串数组 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。于是我的思路到此截止。
  • 于是我的思路的郁结点在于,没有意识到,对于求最小公共部分,始终保留最小的那个数就可以了。
上一篇:bzoj 1002: [FJOI2007]轮状病毒


下一篇:使用JAXB解析xml文件(一)