Day06–哈希表–242. 有效的字母异位词,349. 两个数组的交集,202. 快乐数,1. 两数之和
Day06–哈希表–242. 有效的字母异位词,349. 两个数组的交集,202. 快乐数,1. 两数之和
242. 有效的字母异位词
思路:
1、使用数组当哈希表,遍历第一个数组的时候加一,遍历第二个数组的时候减一,map全是0的时候返回true。
2、map的“hash”算法是[s.charAt(i) - ‘a’]。
class Solution { public boolean isAnagram(String s, String t) { if (s.length() != t.length()) { return false; } int n = s.length(); int[] map = new int[26]; for (int i = 0; i < n; i++) { map[s.charAt(i) - \'a\']++; } for (int i = 0; i < n; i++) { map[t.charAt(i) - \'a\']--; } for (int i = 0; i < 26; i++) { if (map[i] != 0) { return false; } } return true; }}
349. 两个数组的交集
思路:
1、因为要确保元素是唯一的,使用set去存放元素;
2、第一个数组直接遍历,第二个数组使用contains()进行判断;
3、将set转换成int[],可以考虑stream方法
class Solution { public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set = new HashSet<>(); Set<Integer> res = new HashSet<>(); for (int i = 0; i < nums1.length; i++) { set.add(nums1[i]); } for (int i = 0; i < nums2.length; i++) { if (set.contains(nums2[i])) { res.add(nums2[i]); } } // 方法一:手动将set转成int[] int[] result = new int[res.size()]; int p = 0; for (int num : res) { result[p++] = num; } return result; // 方法二:使用stream转 // return res.stream().mapToInt(Integer::intValue).toArray(); }}
其他题解:用数组做map
class Solution { public int[] intersection(int[] nums1, int[] nums2) { // 用数组做map int[] map1 = new int[1001]; int[] map2 = new int[1001]; List<Integer> list = new LinkedList<>(); for (int i = 0; i < nums1.length; i++) { map1[nums1[i]]++; } for (int i = 0; i < nums2.length; i++) { map2[nums2[i]]++; } for (int i = 0; i < 1001; i++) { int tem = Math.min(map1[i], map2[i]); if (tem != 0) { list.add(i); } } return list.stream().mapToInt(Integer::intValue).toArray(); }}
202. 快乐数
思路:
1,注意关键词“无限循环”,意思就是,如果不变成1的话,会在某个数值循环,这时候就要想到去重哈希表,也就是set
2,熟练掌握,对数字分解,对每位数字进行操作。%10就是取末位,/10就是去掉末位。
class Solution { public boolean isHappy(int n) { Set<Integer> set = new HashSet<>(); while (n != 1 && !set.contains(n)) { set.add(n); n = getNextNum(n); } return 1 == n; } private int getNextNum(int num) { int sum = 0; while (num > 0) { int temp = num % 10; sum += temp * temp; num /= 10; } return sum; }}
记录:自己做的时候,还真没想到,怎么退出循环的条件,还得是要仔细读题。然后,熟练练习分解数字的操作。
1. 两数之和
思路:
1,用map存“已经遍历过的元素和它的下标”,key是元素,value是下标。
2,每次存之前,先找map中有没有刚好和nums[i]凑成target的元素存在,也就是map.containsKey(target - nums[i])——注意,这里不能把map.put(nums[i], i);放在if前面,因为如果是[3,3]数组,target=6的话,就会出意外。
class Solution { public int[] twoSum(int[] nums, int target) { int[] res = new int[2]; int n = nums.length; Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < n; i++) { if (map.containsKey(target - nums[i])) { res[0] = i; res[1] = map.get(target - nums[i]); } map.put(nums[i], i); } return res; }}
记录:做了一天做累了,这么简单的题都想不出来。这可是在哈希表单元啊,除了数组,set,还有什么,就是轮到用map了。——当要存一个键值对的时候,要想到map
拓展题
49. 字母异位词分组
438. 找到字符串中所有字母异位词
350. 两个数组的交集 II
思路:和《一》是一样的,只不过,因为这次可以重复出现了,要用list装。
class Solution { public int[] intersect(int[] nums1, int[] nums2) { // 用数组做map int[] map1 = new int[1001]; int[] map2 = new int[1001]; List<Integer> list = new LinkedList<>(); for (int i = 0; i < nums1.length; i++) { map1[nums1[i]]++; } for (int i = 0; i < nums2.length; i++) { map2[nums2[i]]++; } for (int i = 0; i < 1001; i++) { int tem = Math.min(map1[i], map2[i]); if (tem != 0) { while (tem-- > 0) { list.add(i); } } } return list.stream().mapToInt(Integer::intValue).toArray(); }}
对比下面《一》的代码,可以看到,《一》的呢,遇到>0的,就加一次就行;《二》这道题,就是要加n次。
class Solution { public int[] intersect(int[] nums1, int[] nums2) { // 用数组做map int[] map1 = new int[1001]; int[] map2 = new int[1001]; List<Integer> list = new LinkedList<>(); for (int i = 0; i < nums1.length; i++) { map1[nums1[i]]++; } for (int i = 0; i < nums2.length; i++) { map2[nums2[i]]++; } for (int i = 0; i < 1001; i++) { int tem = Math.min(map1[i], map2[i]); if (tem != 0) { list.add(i); } } return list.stream().mapToInt(Integer::intValue).toArray(); }}