705. 设计哈希集合
题目描述
不使用任何内建的哈希表库设计一个哈希集合(HashSet)。
实现 MyHashSet 类:
void add(key)向哈希集合中插入值key。bool contains(key)返回哈希集合中是否存在这个值key。void remove(key)将给定值key从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。
示例:
输入: ["MyHashSet", "add", "add", "contains", "contains", "add", "contains", "remove", "contains"] [[], [1], [2], [1], [3], [2], [2], [2], [2]] 输出: [null, null, null, true, false, null, true, null, false] 解释: MyHashSet myHashSet = new MyHashSet(); myHashSet.add(1); // set = [1] myHashSet.add(2); // set = [1, 2] myHashSet.contains(1); // 返回 True myHashSet.contains(3); // 返回 False ,(未找到) myHashSet.add(2); // set = [1, 2] myHashSet.contains(2); // 返回 True myHashSet.remove(2); // set = [1] myHashSet.contains(2); // 返回 False ,(已移除)
提示:
0 <= key <= 106- 最多调用
104次add、remove和contains
解法
方法一:静态数组实现
思考
需要实现不含重复键的集合,键的范围是 \([0, 10^6]\),操作次数不超过 \(10^4\)。用平衡树或哈希表库函数可以完成,但题目意在自行设计底层存储。
键本身已是非负整数且上界固定,可直接作为下标。开辟长度为 \(10^6+1\) 的布尔数组,添加、删除、查询都变成对单个位置的读写,均为 \(O(1)\)。
空间与值域成正比而非与操作次数成正比,在本题限制下可以接受。
直接创建一个大小为 \(1000001\) 的数组,初始时数组中的每个元素都为 false,表示哈希集合中不存在该元素。
往哈希集合添加元素时,将数组中对应位置的值置为 true;删除元素时,将数组中对应位置的值置为 false;当查询元素是否存在时,直接返回数组中对应位置的值即可。
以上操作的时间复杂度均为 \(O(1)\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
方法二:数组嵌套链表
思考
方法一用值域大小的数组换取 \(O(1)\),当值域远大于实际键数时空间浪费明显。本题操作只有 \(10^4\) 次,真正存放的键很少。
将键对较小的模数取余,散列到固定桶中,每个桶用链表存放冲突键。查找、插入、删除先定位桶再线性扫描该桶,期望长度很短。
取 \(\textit{SIZE}=1000\),空间降到与桶数同阶,单次操作期望接近常数。
我们也可以开辟一个大小为 SIZE=1000 的数组,数组的每个位置是一个链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | |