第三章哈希表2.有效的字母异位词3.两个数组的交集

71 阅读1分钟

哈希表理论基础复习

一般哈希表用于快速判断一个元素是否出现在集合里,查询效率高

使用哈希函数将数据映射为哈希表上的索引

如果两个数据恰好映射到了同一个索引上,这种现象叫做哈希碰撞

解决办法:

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 * 104
  • st 仅包含小写字母

进阶: 如果输入字符串包含 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.两个数组的交集

给定两个数组 nums1nums2 ,返回

它们的交集

。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

示例 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太不熟悉了,多写几遍