代码随想录算法训练营第六天(昨天休息)| 242.有效的字母异位词 ,349. 两个数组的交集,202. 快乐数,1. 两数之和

本文讲述了如何使用哈希表(数组和HashMap)解决LeetCode中的字母异位词检测、两个数组的交集以及两数之和问题,强调了哈希法在处理小规模重复元素和快速查找方面的优势。
摘要由CSDN通过智能技术生成

题目与题解

参考资料:哈希表理论基础

242.有效的字母异位词

题目链接:242.有效的字母异位词

代码随想录题解:242.有效的字母异位词

视频讲解:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词_哔哩哔哩_bilibili

解题思路:

        题目要求统计字符串中每个字符出现的次数,如果两个字符串的每个字符出现频次都相同,则符合要求。对于这种需要统计的对象范围很小的情况,非常适合用数组去统计。

        由于小写字母一共就26个,可以设置一个大小为26的数组,‘a’对应第0个元素,'b'对应第1个元素... ‘z’对应第25个元素,并初始化每个元素为0。遍历第一个字符串,记录每个字符的出现次数;接着遍历第二个字符串,每个字符出现一次,就在数组中对当前字符的频次减去1;最后判断数组是否为全0,如果是,则这两个字符串是有效的字母异位词。

class Solution {
    public boolean isAnagram(String s, String t) {
		// 数组实现
		int[] count = new int[26];
		Arrays.fill(count, 0); // 初始化数组为全0,不初始化的话默认也是全0
		for (int i = 0; i < s.length(); i++) {
			count[s.charAt(i) - 'a'] += 1;
		}
		for (int i = 0; i < t.length(); i++) {
			count[t.charAt(i) - 'a'] -= 1;
		}
		for (int i = 0; i < 26; i++) {
			if (count[i] != 0) return false;
		}
		return true;
    }

        题目还给出了拓展要求,假设字符串含unicode字符。经过查询,unicode字符的范围在0x0000到0x10FFFF,远比26个小写字母多很多。此时数组法固然也可以解决相应的问题,但输入的字符串长度远小于unicode字符串的范畴,此方法会导致大量的空间浪费。此时用键值对,即map类型的方法更适合存储数据。这样,分别用两个map对象存储两个字符串中字符出现的频次,最后对比两个map的结果是否相同即可。

class Solution {
    public boolean isAnagram(String s, String t) {
		// HashMap实现
		HashMap<Character, Integer> maps = new HashMap<>();
		for (int i = 0; i < s.length(); i++) {
			if (maps.containsKey(s.charAt(i))) {
				maps.put(s.charAt(i), maps.get(s.charAt(i)) + 1);
			} else {
				maps.put(s.charAt(i), 1);
			}
		}
		HashMap<Character, Integer> mapt = new HashMap<>();
		for (int i = 0; i < t.length(); i++) {
			if (mapt.containsKey(t.charAt(i))) {
				mapt.put(t.charAt(i), mapt.get(t.charAt(i)) + 1);
			} else {
				mapt.put(t.charAt(i), 1);
			}
		}
        return maps.equals(mapt);
    }
}

看完代码随想录之后的想法 

        数组法存储空间浪费少,哈希法查找对比效率高,都挺好。

遇到的困难

        题目本身不难,难在我不记得java里面要从字符串里面取字符应该用charAt方法,平常真的不太用,这次记住就行。

349. 两个数组的交集

题目链接:349. 两个数组的交集

代码随想录题解:349. 两个数组的交集

视频讲解:学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集_哔哩哔哩_bilibili

解题思路:

        交集这个概念一出,对应了set这一数据结构,利用set特性去除数组中的重复元素,然后再将两个set进行比对会比较高效。

        分别基于输入的数组,创建两个set类型变量,遍历数组,将每个元素都存入set变量,会得到每个数组对应的集合结果;接着,再分别遍历两个集合,将每个元素存入新的set变量,得到交集结果;最后将set转换为数组类型,返回结果。

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
		// 用set
		HashSet<Integer> nums1Set = new HashSet<>();
		for (int num : nums1) {
			nums1Set.add(num);
		}
		HashSet<Integer> resultSet = new HashSet<>();
		for (int num : nums2) {
			if (nums1Set.contains(num)) {
				resultSet.add(num);
			}
		}
		int[] result = new int[resultSet.size()];
		int index = 0;
		for (int num : resultSet) {
			result[index++] = num;
		}
		return result;
    }
}

看完代码随想录之后的想法 

        看到输出结果唯一,就要想到去重,对应的就是set容器。

        由于本题限制了数组大小为1000以内,数量不大,可以用数组代替哈希表进行计算。如果没有限制范围,数组法就不适用了。

随想录题解如下:

class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int[] hash1 = new int[1002];
        int[] hash2 = new int[1002];
        for(int i : nums1)
            hash1[i]++;
        for(int i : nums2)
            hash2[i]++;
        List<Integer> resList = new ArrayList<>();
        for(int i = 0; i < 1002; i++)
            if(hash1[i] > 0 && hash2[i] > 0)
                resList.add(i);
        int index = 0;
        int res[] = new int[resList.size()];
        for(int i : resList)
            res[index++] = i;
        return res;
    }
}

遇到的困难

        因为题目已经说了用集合,众所周知英文字母set就有集合的意思,其实也就对应了java里面的hashset数据类型,很容易想到。但是写的时候,同样不知道怎么用set类型,与map不同,插入元素是set.add,而map是map.put。

202. 快乐数

题目链接:202. 快乐数

代码随想录题解:202. 快乐数

解题思路:

        一个数字通过快乐数的计算过程,最终只能有两个结果:为1,或是无限循环,而无限循环就意味着之前算出来的平方和不止一次出现。显然可以用set类型记录结果,保证记录的平方和没有重复,直到第一个重复的结果出现,返回false;如果中途平方和为1,返回true。

        

class Solution {
    public boolean isHappy(int n) {
		Set<Integer> squareSums = new HashSet<>();
		int loopResult = n;
		while (loopResult != 1 ) {
			int squareSum = 0;
			int num = loopResult % 10;
			while (loopResult != 0 ) {
				squareSum += num*num;
				loopResult /= 10;
				num = loopResult % 10;
			}
			if (squareSums.contains(squareSum)) return false;
			loopResult = squareSum;
			squareSums.add(loopResult);
		}
		return true;
    }
}

看完代码随想录之后的想法 

        思路是差不多的,随想录另写了一个小方法getNextNumber用于记录每次循环后得到的平方和结果,看起来更清晰一点。

遇到的困难

        想的时候很容易,写的时候脑子不太清楚,尤其是在计算每一次的平方和时,写错了好几个地方,debug了三次才通过。第一次得到了死循环,因为内层循环的条件错写成num != 0;并且还忘记在内层循环更新num的值了;还有return false这一句,一开始放在了外层循环的最后一句,那由于前一步已经把这次的平方和结果塞进去了,马上就return false了,逻辑顺序出错。这种涉及到细节的过程,一定要带入一个数字试试,仔细一点,否则很容易出错。

1. 两数之和 

题目链接:​​​​​​​1. 两数之和 

代码随想录题解:​​​​​​​1. 两数之和 

视频讲解:梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!_哔哩哔哩_bilibili

解题思路:

        虽然知道题目应该要用哈希表做,但一时半会儿没想起来,所以先用暴力法给一个结果。两层循环遍历数组,第一层取数组中的每一个元素,第二层查找数组中为target - nums[i]的元素,如果找到了就返回下标。要小心出现target - nums[i] = nums[i]的情况,第二层循环的j不能等于i。     

    class Solution {
        public int[] twoSum(int[] nums, int target) {
            // 暴力法
            for (int i = 0; i < nums.length; i++) {
                int result = target - nums[i];
                for (int j = 0; j < nums.length; j++) {
                    if (result == nums[j] && j != i) {
                        return new int[]{i, j};
                    }
                }
            }
            return new int[]{};
        }
    }

看完代码随想录之后的想法 

        本来想试着用map类型解决,但是第一次想只要统计数组中每个元素的出现频次,就可以很容易的查找是否存在一个合适的数,但突然发现结果要求返回其下标,那该方法作废。

        最后还是看了随想录的做法,思路是用map类型存键值对,key是数字,value是对应的下标,然后查找target-nums[i]对应的结果是否在map的key中。

        我第一次看到的时候觉得很奇怪,如果数组中存在一样的数,那么遍历后该数的新下标不就把老下标覆盖了吗?假设target正好等于两个一样的数之和,那不是根本无法取得前一个数的下标吗?

        后来看了算法,才发现其实是一边查询一边把不符合要求的数字插入map中的。如果提前找到了结果,就不用把后面的数再一一插进去计算查找了。这意味着,如果数组中确实存在两个相同的数之和等于target,那么第一个数已经存入map的情况下,当遍历到第二个数时,代码会先判断这个数是否符合要求,符合就直接返回结果,不需要再把它插入了,很巧妙。

    class Solution {
        public int[] twoSum(int[] nums, int target) {
			Map<Integer, Integer> map = new HashMap<>();
            for (int i = 0; i < nums.length; i++) {
                if (map.containsKey(target - nums[i])) {
                    return new int[]{map.get(target - nums[i]), i};
                } else {
                    map.put(nums[i], i);
                }
            }
            return new int[]{};
        }
    }

遇到的困难

        hash法一开始想岔了没想出来。以后要注意,但凡涉及到无重复的,唯一的,要快速查找的,用set和map会更灵活。

今日收获

        复习了hash表的用法。哈希法的基础知识其实挺复杂的,我光看了一遍有点记不住。但是目前可以先把它们的用法和基本原理掌握一下,先保证下次会用。

        题目是分了两天做的,晚上开始的有点晚,很困,效率不高,加起来连上写博客大概也花了三个小时。这强度逐渐吃不消了呀,加油加油。

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值