什么时哈希表
哈希表是根据关键码值(key-value)而直接进行访问的数据结构,它通过把关键码值映射到表的一个位置来访问记录,以加快查找的速度
直接来说数组就是一张哈希表
我们可以通过索引值对元素进行查找
常见的三种哈希结构
- 数组
- set集合
- map(映射)
当我们遇到了一个要判断一个元素是否出现在集合里的时候,就要考虑哈希法了
但是哈希法是牺牲空间换取时间的,因为我们要使用额外的数组,set,map来存放数据,才能实现快速的查找。
哈希表之有效的字母异位词
tip:数组是简单的哈希表,但是数组的大小受限。
哈希表之 set
class Solution {
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
int[] res=new int[26];
for(int i = 0;i<s.length();i++){
res[s.charAt(i)-'a']++;
}
for(int i = 0;i<t.length();i++){
res[t.charAt(i)-'a']--;
}
for(int i = 0;i<26;i++){
if(res[i]!=0){
return false;
}
}
return true;
}
}
两个数组的交集
方法一、 三个哈希表求解
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set<Integer> n1=new HashSet<>();
Set<Integer> n2=new HashSet<>();
for(int num1:nums1){
n1.add(num1);
}
for(int num2:nums2){
n2.add(num2);
}
Set<Integer> res=new HashSet<>();
for(int n:n2){
if(n1.contains(n)){
res.add(n);
}
}
int[] ans =new int[res.size()];
int k=0;
for(int r:res){
ans[k]=r;
k++;
}
return ans;
}
}
方法二、
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int length1 = nums1.length, length2 = nums2.length;
int index1 = 0, index2 = 0, index=0;
int[] res = new int[length1+length2];
while(index1 < length1 && index2 < length2){
int num1=nums1[index1],num2=nums2[index2];
if(num1==num2){
if(index==0 || num1!=res[index-1]){
res[index++]=num1;
}
index1++;
index2++;
}else if(num1<num2){
index1++;
}else{
index2++;
}
}
return Arrays.copyOfRange(res,0,index);
}
}
哈希表之快乐数
递归+哈希表
class Solution {
Set<Integer> set = new HashSet<>();
int pop =0;
public boolean isHappy(int n) {
return helper(n)==1?true:false;
}
public int helper(int n){
if(n==1 ||set.contains(n)) return n;
set.add(n);
int sum =0;
while(n%10!=0||n>0){
pop = n%10;
sum+=pop*pop;
n=n/10;
}
return helper(sum);
}
}
哈希表之map
map之两数之和、
这道题知道用map做 但是忘记map.containsKey了想了半天不知道怎么做 还是看解析会的 烦!
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};
}
map.put(nums[i],i);
}
return new int [0];
}
}
map之四数相加
class Solution {
public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
int n = A.length;
Map<Integer,Integer> map = new HashMap<>();
for(int i =0;i<n;i++){
for(int j=0;j<n;j++){
map.put(A[i]+B[j],map.getOrDefault(A[i]+B[j],0)+1);
}
}
int count =0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(map.containsKey(-C[i]-D[j])){
count+=map.get(-C[i]-D[j]);
}
}
}
return count;
}
}
map之赎金信
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
Map<Character,Integer> map = new HashMap<>();
for(int i =0;i<magazine.length();i++){
map.put(magazine.charAt(i),map.getOrDefault(magazine.charAt(i),0)+1);
}
for(int i = 0;i<ransomNote.length();i++){
if(!map.containsKey(ransomNote.charAt(i))||map.get(ransomNote.charAt(i))<=0){
return false;
}
map.put(ransomNote.charAt(i),map.getOrDefault(ransomNote.charAt(i),0)-1);
}
return true;
}
}
三数之和、混在map中的双指针
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
for(int l1=0;l1<nums.length-2;l1++){
//去除相同元素
if(l1>0 && nums[l1]==nums[l1-1]){
continue;
}
int rigth = nums.length-1;
for(int i=l1+1;i<nums.length-1;i++){
// 去除相同元素
if(i>l1+1 && nums[i]==nums[i-1]){
continue;
}
while (nums[l1]+nums[i]+nums[rigth]<0 && i<rigth){
i++;
}
while(nums[l1]+nums[i]+nums[rigth]>0 && i<rigth){
rigth--;
}
if(i==rigth){
break;
}
//当等于0时将元素装进链表
if(nums[l1]+nums[i]+nums[rigth]==0){
List<Integer> res = new ArrayList<>();
res.add(nums[l1]);
res.add(nums[i]);
res.add(nums[rigth]);
ans.add(res);
}
}
}
return ans;
}
}
四数之和、隐藏在map中的排序+双指针
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int length=nums.length;
for(int i =0;i<length-3;i++){
if(i>0 && nums[i]==nums[i-1]){
continue;
}
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if (nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for(int j =i+1;j<length-2;j++){
if(j>i+1 && nums[j]==nums[j-1]){
continue;
}
if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if (nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int right=length-1,left=j+1;
while(left<right){
int sum = nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target){
List<Integer> ans = new ArrayList<>();
ans.add(nums[i]);
ans.add(nums[j]);
ans.add(nums[left]);
ans.add(nums[right]);
res.add(ans);
while(left<right && nums[left]==nums[left+1]){
left++;
}
left++;
while(left<right && nums[right-1]==nums[right]){
right--;
}
right--;
}else if(sum<target){
left++;
}else{
right--;
}
}
}
}
return res;
}
}
哈希表总结
- 一般来说哈希表都是用来迅速判断一个元素是否出现在集合中
- 哈希函数和哈希碰撞在哈希表中的作用
- 哈希函数是把要传入的Key映射到符号表的索引上
- 哈希碰撞处理有多个key映射到相同的索引上时的情景,处理碰撞的普遍方式是拉链法和线性探测法
- 常见的三种哈希结构
- 数组
- set(集合)
- map(映射)
数组作为哈希表的应用场景
数组是简单的哈希表,但是数组的大小是受限的,受到系统栈空间的限制,当数组空间大而哈希值比较少,特别分散,跨度较大时,使用数组就会造成空间浪费。
set作为哈希表的应用场景
当数组不行的时候 这时候就用set呗
map作为哈希表的应用场景
数组大小受限
set里面只能放一个元素
当我们需要对两个值进行记录时 就需要用到map 了