12 |「哈希表」必刷题

文章介绍了哈希表的基础知识,包括其作用、组成、哈希冲突及其解决方法。重点讨论了Set和Map的数据结构特性,并通过LeetCode的两道面试题——两数之和和唯一元素的和,展示了哈希表在解决实际问题中的应用和时间效率。

前言

前言:刷「哈希表」高频面试题。

一. 基础回顾

详细介绍参考 11 讲: 哈希表简析 (点击链接直达)

1. 为什么需要哈希表

对于数组 a[i] = x,下标 i 只能是某段范围内的某一较小的整数,当 i 很大(实数)或是字符串,很难通过下标对数组元素进行访问。

2. 什么是哈希表

哈希表又称为散列表,是一种可以通过任意的关键吗(key)直接进行访问的数据结构。

哈希表的本质是将一个复杂信息的集合通过哈希函数映射成一个小的范围的集合作为索引。

3. 组成

哈希表由两部分组成。

1)数据结构

一部分是实现的数据结构,常是链表或数组实现。但是,链表不支持索引来访问,数组只支持一个范围小的整数作为下标,这样就引出了另一部分。

2)哈希函数

另一部分是哈希函数,通过输入关键码 key,返回哈希表数据结构的索引。
通过将任意一个 key(复杂信息数据:大的整数、实数、字符串)经过哈希函数映射成一个简单的信息(小的整数)。

3)总结

哈希函数对外封装为一个可以通过关键码 key 直接访问的数据结构:hash_table[key] = value

实际上是在数据结构中通过哈希函数 hash(key) 计算得到位置,之后在该位置存储 value

data_structure[hash(key)] = value,其中 data_structure 为数组或链表。

4. 哈希冲突

1)产生原因

将一个大的集合映射成一个小的集合会有冲突(碰撞),哈希碰撞为两个不同的 key 计算出同样的 Hash 结果。

2)解决方法(开散列)

  • Hash 函数依然用于计算数组下标;
  • 数组的每个位置存储链表的表头指针;
  • 每个链表存储具有同样 Hash 值对应要存储的值;

5. 集合(Set)与映射(Map)

集合与映射是两个用来维护信息的基本数据结构。

1)Set

底层实现
  • 集合(set)是一个抽象的概念(一个封装),底层实现通过哈希表或平衡二叉树。
特点
  • 集合用来存储不重复的元素
  • 有序集合一般用平衡二叉树来实现,时间复杂度为 O ( l o g N ) O(logN) O(logN)
  • 无序集合一般用哈希表来实现,时间复杂度位 O ( 1 ) O(1) O(1)

2)Map

底层实现
  • 映射(map)也是一个抽象的概念(一个封装),底层实现通过哈希表或平衡二叉树。
特点
  • 用来存储不重复的键值对(key-value
  • 有序集合,遍历时按照 key 大小排列,实现一般用平衡二叉树,时间复杂度为 O ( l o g N ) O(logN) O(logN)
  • 无序集合一般用哈希表来实现,时间复杂度为 O ( 1 ) O(1) O(1)

二. 高频面试题

1. 例题

LeetCode 1 两数之和
1)题目链接

原题链接:两数之和(点击链接直达)

2) 算法思路
  • for i = 0 ~ n-1
  • search if (target - nums[i]) exists in nums[0,i-1]
  • nums[0,i-1]哈希表来维护;
3)源码剖析
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> heap;		`			//(1)
        int n = nums.size();

        for (int i = 0; i < n; i ++)					//(2)
        {
            int r = target - nums[i];					//(3)
            if (heap.count(r)) return {heap[r], i};		//(4)
            heap[nums[i]] = i;							//(5)
        } 
        return {};
    }
};
  • (1)定义哈希表 heap,<value, index> ;
  • (2)遍历整个数组;
  • (3)rnums[i] 相加和为 target
  • (4)在哈希表中查找 r 是否存在;
  • (5) nums[0,i-1] 用哈希表来维护;
4)时间复杂度

         O ( n ) O(n) O(n)


LeetCode 1748 唯一元素的和
1)题目链接

原题链接:唯一元素的和(点击链接直达)

2) 算法思路
  • 用数组模拟哈希表;
  • 哈希表用来存储原数组中每个元素出现的次数;
  • 遍历原数组,并查询每个元素在哈希表中出现的次数,如果出现一次,则求和;
3)源码剖析
class Solution {
public:
    int sumOfUnique(vector<int>& nums) {
        vector<int> heap(105, 0);						//(1)
        int n = nums.size();
        int sum = 0;									//(2)

        for (int i = 0; i < n; i ++) heap[nums[i]] ++;	//(3)
        for (int i = 0; i < n; i ++)					
        {
            if (heap[nums[i]] == 1)						//(4)
                sum += nums[i];
        }
        return sum;
    }
};
  • 定义一个数组,长度为 105,所有元素值初始化为 0
  • 初始化和为 0
  • 记录原数组中每个元素出现的次数;
  • 遍历整个原数组,查询出现一次的元素,并求和;
4)时间复杂度

         O ( n ) O(n) O(n)


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个写代码的修车工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值