哈希表理论基础复习
一般哈希表用于快速判断一个元素是否出现在集合里,查询效率高
使用哈希函数将数据映射为哈希表上的索引
如果两个数据恰好映射到了同一个索引上,这种现象叫做哈希碰撞
解决办法:
1、拉链法:碰撞位置建立链表
2、线性探测法:向下找一个空位,要求tableSize大于dataSize
Java中的哈希结构
代码随想录里面讲的是C++的哈希结构,Java中的哈希结构主要体现在以下几个类中:HashMap、HashSet、Hashtable、LinkedHashMap、ConcurrentHashMap.
相关资料Java集合常见面试题总结(下) | JavaGuide(Java面试 + 学习指南)
HashMap 源码分析 | JavaGuide(Java面试 + 学习指南)
ConcurrentHashMap 源码分析 | JavaGuide(Java面试 + 学习指南)
LinkedHashMap 源码分析 | JavaGuide(Java面试 + 学习指南)
242.有效的字母异位词
给定两个字符串
s和t,编写一个函数来判断
t是否是s的字母异位词。
**注意:**若s和t中每个字符出现的次数都相同,则称s和t互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
提示:
1 <= s.length, t.length <= 5 * 104s和t仅包含小写字母
进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
题解
s与t中只有小写字母,那么定义两个26长度的数组,统计字符出现的次数,最后再比较两个数组是否相等,仅需遍历3次即可。
class Solution { public boolean isAnagram(String s, String t) { int[] hash1=new int[26]; int[] hash2=new int[26]; for(int i=0;i<s.length();i++){ hash1[s.charAt(i)%26]++; } for (int i = 0; i < t.length(); i++) { hash2[t.charAt(i)%26]++; } for(int i=0;i<26;i++){ if(hash1[i]!=hash2[i]) return false; } return true; }}
但是这样就定义了两个26长度的数组,其实可以用一个数组就可以解决,在遍历s的时候把数组对应值++,遍历t的时候数组对应值--即可。
class Solution { public boolean isAnagram(String s, String t) { int[] hash=new int[26]; for(int i=0;i<s.length();i++){ hash[s.charAt(i)%26]++; } for (int i = 0; i < t.length(); i++) { hash[t.charAt(i)%26]--; } for(int i=0;i<26;i++){ if(hash[i]!=0) return false; } return true; }}
看了下力扣的运行时间,有人只花了1ms,我的还要3ms,参考了一下,发现直接把字符串转成char数组会更快,应该是调charAt的时候有一点慢了。
class Solution { public boolean isAnagram(String s, String t) { char[] S = s.toCharArray(); char[] T = t.toCharArray(); int[] hash = new int[26]; for(int i = 0;i<S.length;i++){ hash[S[i]-'a']++; } for(int i = 0;i<T.length;i++){ hash[T[i]-'a']--; } for(int i =0;i<hash.length;i++){ if(hash[i]!=0){ return false; } } return true; }}
349.两个数组的交集
给定两个数组 nums1 和 nums2 ,返回
它们的交集
。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
提示:
-
1 <= nums1.length, nums2.length <= 1000 -
0 <= nums1[i], nums2[i] <= 1000
题解
第一反应还是两个数组来存出现过的数字,但是消耗的空间有点大,先把结果放到List中,再根据List长度定义数组。
但是看力扣运行时间比空间少的方法短,可能是空间换时间了。
class Solution { public int[] intersection(int[] nums1, int[] nums2) { int[] hash1=new int[1001]; int[] hash2=new int[1001]; for(int i=0;i<nums1.length;i++){ hash1[nums1[i]]++; } for(int i=0;i<nums2.length;i++){ hash2[nums2[i]]++; } List<Integer> target=new ArrayList<>(); for(int i=0;i<1001;i++){ if(hash1[i]>0&&hash2[i]>0) target.add(i); } int[] ans=new int[target.size()]; int index=0; for(int a:target){ ans[index++]=a; } return ans; }}
另一种方法使用了HashSet数据结构,大大节省了空间
class Solution { public int[] intersection(int[] nums1, int[] nums2) { Set<Integer> cont=new HashSet<>(); Set<Integer> simm=new HashSet<>(); for(int i:nums1){ cont.add(i); } for (int i:nums2) { if (cont.contains(i)){ simm.add(i); } } int[] ans=new int[simm.size()]; int j=0; for(int i:simm){ ans[j++]=i; } return ans; }}
总结
HashSet太不熟悉了,多写几遍