哈希表学习笔记
- 哈希表简介
- 哈希函数
- 哈希冲突
- 练习题目
- 1.[存在重复元素](https://leetcode.cn/problems/contains-duplicate/description/)
- 2.[存在重复元素 II](https://leetcode.cn/problems/contains-duplicate-ii/description/)
- 3.[有效的数独](https://leetcode.cn/problems/valid-sudoku/description/)
- 4.[两个数组的交集](https://leetcode.cn/problems/intersection-of-two-arrays/description/)
- 5.[两个数组的交集 II](https://leetcode.cn/problems/intersection-of-two-arrays-ii/description/)
- 6.[设计哈希映射](https://leetcode.cn/problems/design-hashmap/description/)
- 参考资料
哈希表简介
哈希表(Hash Table):也叫散列表。是根据关键码值(key value)直接进行访问的数据结构。
哈希表通过【键 key】和【映射函数 Hash(key)】计算出对应的【值 value】,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数就叫做【哈希函数(散列函数)】,存放记录的数组叫做【哈希表【散列表】】。
哈希函数
哈希函数(Hash Function):将哈希表中的元素的关键键值映射为元素存储位置的函数。
哈希函数是哈希表中最重要的部分。一般来说,哈希函数会满足以下几个条件:
- 哈希函数应该易于计算,并且尽量使计算出来的索引值均匀分布。
- 哈希函数计算得到的哈希值是一个固定长度的输出值。
- 如果hash(Key1)不等于Hash(key2),那么key1、key2一定不相等。
- 如果Hash(key1)等于Hash(key2),那么key1、key2可能相等,也可能不相等(会发生哈希碰撞)。
哈希冲突
哈希冲突(Hash collision):不同的关键字通过同一个哈希函数得到同一哈希地址。
练习题目
1.存在重复元素
class Solution {
public boolean containsDuplicate(int[] nums) {
//双重循环O(n^2)
// for(int i=0;i<nums.length-1;i++){
// for(int j=i+1;j<nums.length;j++){
// if(nums[i]==nums[j]){
// return true;
// }
// }
// }
// return false;
//排序后相邻比较O(nLogn)
// Arrays.sort(nums);
// for(int i=0;i<nums.length-1;i++){
// if(nums[i]==nums[i+1]){
// return true;
// }
// }
// return false;
//使用哈希表O(N)
Set<Integer> set = new HashSet<Integer>();
for(int i=0;i<nums.length;i++){
if(set.contains(nums[i])){
return true;
}
set.add(nums[i]);
}
return false;
}
}
2.存在重复元素 II
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
//双重循环O(N^2)
// for(int i=0;i<nums.length-1;i++){
// for(int j=i+1;j<nums.length;j++){
// if(nums[i]==nums[j]&&Math.abs(i-j)<=k){
// return true;
// }
// }
// }
// return false;
//HashMapO(N)
HashMap<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
if(map.get(nums[i])!=null&&Math.abs(map.get(nums[i])-i)<=k){
return true;
}
map.put(nums[i],i);
}
return false;
}
}
3.有效的数独
class Solution {
public boolean isValidSudoku(char[][] board) {
//HashMapO(1),挺呆的这个暴力求
HashMap<Character,Integer> map = new HashMap<>();
// 横着
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
char tmp1 = board[i][j];
if(map.containsKey(tmp1)&&tmp1!='.'){
return false;
}
map.put(tmp1,1);
}
map.clear();
}
//竖着
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
char tmp1 = board[j][i];
if(map.containsKey(tmp1)&&tmp1!='.'){
return false;
}
map.put(tmp1,1);
}
map.clear();
}
//小方块
for(int f1=1;f1<4;f1++){
for(int f2=1;f2<4;f2++){
for(int i=3*(f1-1);i<3*f1;i++){
for(int j=3*(f2-1);j<3*f2;j++){
char tmp1 = board[j][i];
if(map.containsKey(tmp1)&&tmp1!='.'){
return false;
}
map.put(tmp1,1);
}
}
map.clear();
}
}
return true;
}
}
4.两个数组的交集
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
//双重循环O(n^2)
// HashSet<Integer> set = new HashSet<Integer>();
// for(int i=0;i<nums1.length;i++){
// for(int j=0;j<nums2.length;j++){
// if(nums1[i]==nums2[j]){
// //需要去重
// set.add(nums1[i]);
// }
// }
// }
// int arr[] = new int[set.size()];
// int cnt=0;
// for(Integer num :set){
// arr[cnt++]=num;
// }
// return arr;
//使用set集合O(m+n)
Set<Integer> set1 = new HashSet<Integer>();
Set<Integer> set2 = new HashSet<Integer>();
for(Integer num:nums1){
set1.add(num);
}
for(Integer num:nums2){
set2.add(num);
}
return getResult(set1,set2);
}
public int[] getResult(Set<Integer> set1,Set<Integer>set2){
if(set1.size()<set2.size()){
return getResult(set2,set1);
}
//去重
Set<Integer> set3 = new HashSet<Integer>();
for(Integer num:set1){
if(set2.contains(num)){
set3.add(num);
}
}
//转换为数组
int[] arr = new int[set3.size()];
int cnt=0;
for(Integer num:set3){
arr[cnt++] = num;
}
return arr;
}
}
5.两个数组的交集 II
class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
Map<Integer,Integer> map1 = new HashMap<>();
Map<Integer,Integer> map2 = new HashMap<>();
//将数组的值转换到HashMap
for(Integer num :nums1){
if(map1.containsKey(num)){
map1.put(num,map1.get(num)+1);
}
else{
map1.put(num, 1);
}
}
for(Integer num :nums2){
if(map2.containsKey(num)){
map2.put(num,map2.get(num)+1);
}else{
map2.put(num,1);
}
}
return getResult(map1,map2);
}
public int[] getResult(Map<Integer,Integer>map1,Map<Integer,Integer>map2){
int cnt=0;
Map<Integer,Integer> map3 = new HashMap<>();
for(Integer key:map1.keySet()){
if(map2.containsKey(key)){
if(map1.get(key)<map2.get(key)){
map3.put(key,map1.get(key));
}else{
map3.put(key,map2.get(key));
}
}
}
//遍历map3
for(Integer num :map3.values()){
cnt+=num;
}
int[] arr = new int[cnt];
int n=0;
for(Integer num :map3.keySet()){
int temp = map3.get(num);
for(int i=0;i<temp;i++){
arr[n++] = num;
}
}
return arr;
}
}
6.设计哈希映射
class MyHashMap {
private class Pair {
private int key;
private int value;
public Pair(int key, int value) {
this.key = key;
this.value = value;
}
public int getKey() {
return key;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
private static final int BASE = 769;
private LinkedList[] data;
//初始化
public MyHashMap() {
data = new LinkedList[BASE];
for(int i=0;i<BASE;i++){
data[i] = new LinkedList<Pair>();
}
}
public void put(int key, int value) {
int h = hash(key);
Iterator<Pair> iterator = data[h].iterator();
while(iterator.hasNext()){
Pair pair = iterator.next();
if(pair.getKey()==key){
pair.setValue(value);
return;
}
}
data[h].offerLast(new Pair(key,value));
}
public int get(int key) {
int h = hash(key);
Iterator<Pair>iterator = data[h].iterator();
while(iterator.hasNext()){
Pair pair = iterator.next();
if(pair.getKey()==key){
return pair.value;
}
}
return -1;
}
public void remove(int key) {
int h = hash(key);
Iterator<Pair> iterator = data[h].iterator();
while (iterator.hasNext()) {
Pair pair = iterator.next();
if (pair.key == key) {
data[h].remove(pair);
return;
}
}
}
private static int hash(int key) {
return key % BASE;
}
}
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap obj = new MyHashMap();
* obj.put(key,value);
* int param_2 = obj.get(key);
* obj.remove(key);
*/
参考资料
- 【博文】哈希表-Datawhale