算法day05-哈希表篇 (1)
目录
- 哈希表理论基础
- 242 有效的字母异位词
- 349 两个数组的交集
- 202 快乐数
- 1 两数之和
一、理论基础
哈希表(hash table),散列表。一般哈希表用来快速判断一个元素是否出现集合里,只需要O(1)复杂度就可以做到,不需要遍历。
三种方法:数组、set、map
哈希碰撞:两个数据哈希到了同一个位置。解决方法:1)拉链法。2)线性探测法。
(url:哈希表)
若一道题目让你判断某个元素是否出现过,这样就可以考虑使用哈希表。
二、有效的字母异位词
思路:这里是用hashMap来做。异位词:字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语,并使用所有原字母一次。这里没有选择建立两个hashmap,而是只用一个map来记录一个数组中元素出现的次数,然后在遍历另一个数组的时候,用消耗的思想来做。
class Solution { public boolean isAnagram(String s, String t) { //将两个字符串拆解成字符数组,再存储到hashset中 char[] ss = s.toCharArray(); char[] tt = t.toCharArray(); if(ss.length != tt.length){ //双重保证 return false; } Map<Character, Integer> map = new HashMap<>(); int flag = ss.length; for(char c : ss){ map.put(c, map.getOrDefault(c,0)+1); } for(char c : tt){ map.put(c, map.getOrDefault(c,0)-1); if(map.get(c) < 0){ //这里会让另一个set消耗的次数不超过本身的次数 return false; } } return true; } } //时间复杂度:O(N) //空间复杂度:O(S),S为字符集大小,此处S=26
三、两个数组的交集
思路:这里我们将一个数组的值存到set中(不重复)。然后遍历另一个数组,看这里的元素是否在set中出现过,若出现过则加入到res中(但这里要判断不能存重复的值!!)。我们选择在第一次contains时就把该元素从set中移除,下次再遇到就不会加入到res中了。
若存储的数字很大的话,就不太适合用数组。
class Solution { public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> set = new HashSet<>(); int[] res = new int[Math.min(nums1.length, nums2.length)]; for(int num : nums1){ set.add(num); //将nums1中的元素存入set(不重复) } int i = 0; for(int num : nums2){ //如果set中包含nums2中的元素,则将其加入到res中 if(set.contains(num)){ set.remove(num); //把num从原本的set里面移除,防止重复判断 res[i] = num; i++; } } return Arrays.copyOf(res, i); //这里i是开区间!不然要i-1 } } //时间复杂度:O(N+M) //空间复杂度:O(N),最坏情况
四、快乐数
方法一:用哈希集合来判断是否存在循环值,若存在则不可能到1。
class Solution { public boolean isHappy(int n) { Set<Integer> set = new HashSet<>(); int sum = 0; while(true){ while(n != 0){ int num = n % 10; sum += num * num; n = n / 10; } n = sum; //再次对sum处理 sum = 0; if(n == 1){ return true; } if(set.contains(n)){ return false; //循环了就到不了1 } set.add(n); } } }
方法二:用快慢指针来做,让慢指针每次做一次计算,快指针做两次计算。若发现快指针满足最后的条件或者快慢指针相遇(存在循环值),则退出循环。最后判断快指针计算出的值是否为1。
class Solution { public boolean isHappy(int n) { int slow = n; int fast = getNext(n); while(fast != 1 && slow != fast){ slow = getNext(slow); fast = getNext(getNext(fast)); } return fast == 1; } public int getNext(int n){ int sum = 0; while(n > 0){ int d = n % 10; n = n /10; sum += d*d; } return sum; } } //时间复杂度:O(logn) //空间复杂度:O(1)
五、两数之和
class Solution { public int[] twoSum(int[] nums, int target) { Map<Integer, Integer> map = new HashMap<>(); for(int i=0; i<nums.length; i++){ //先判断map中是否存在target-nums[i] if(map.containsKey(target-nums[i])){ return new int[]{i, map.get(target-nums[i])}; } map.put(nums[i], i); } throw new IllegalArgumentException("No two sum solution"); } } //时间复杂度:O(N) //空间复杂度:O(N)