哈希表的基础知识
哈希表是一种非常高效的数据结构,它允许我们快速地插入、查找和删除数据。 想象一下你有一本电话簿,里面列出了很多人的名字和他们的电话号码。如果我们想要找到某个人的电话号码,通常需要从头开始一页页翻找,直到找到为止。这种方法效率很低,特别是当电话簿非常厚的时候。
现在假设我们有一种魔法,可以让我们瞬间跳转到电话簿中的任何一页。如果我们知道一个人名字的首字母,我们就可以直接翻到以这个字母开头的部分。这就是哈希表的基本思想:通过某种方式(称为“哈希函数”)将数据映射到一个特定的位置上,这样我们就可以直接定位到我们需要的信息
当我们意识到需要在某个集合中查找值时,就可以用到哈希表。
具体来说,哈希表的工作流程如下:
-
哈希函数:
- 我们使用一个哈希函数来计算每个键(比如人的名字)对应的索引位置。这个函数接受键作为输入,并返回一个整数,这个整数就是键在数组中的位置。
-
存储:
- 哈希表本质上是一个数组,每个位置(或称为“槽”)可以用来存储键值对。
- 当我们需要添加一个新的键值对时,我们会使用哈希函数计算出键对应的数组索引,然后将键值对存放到该索引处。
-
查找:
- 当我们需要查找某个键对应的值时,我们同样使用哈希函数计算出该键应该位于的数组索引,然后直接访问该位置获取值。
但是,这里有一个问题,那就是两个不同的键可能会被哈希函数映射到同一个位置上,这种情况称为“哈希冲突”。为了解决这个问题,有两种常见的方法:
- 链地址法:每个数组位置都指向一个链表,当发生冲突时,就将新的键值对添加到链表中。
- 开放寻址法:当发生冲突时,会寻找下一个可用的位置(例如线性探测或二次探测)来存放键值对。
总的来说,哈希表通过哈希函数将键映射到数组中的位置,使得数据的查找变得非常快。理想情况下,查找的时间复杂度接近 O(1),即常数时间。当然,在实际应用中,还需要考虑哈希函数的设计、负载因子等因素,以保证性能和效率。
242. 有效的字母异位词 - 力扣(LeetCode)
class Solution {
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
HashMap<Character, Integer> mapS = new HashMap<>();
HashMap<Character, Integer> mapT = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
mapS.put(c, mapS.getOrDefault(c, 0) + 1);
}
for (int i = 0; i < s.length(); i++) {
char c = t.charAt(i);
mapT.put(c, mapT.getOrDefault(c, 0) + 1);
}
if (mapS.equals(mapT)) {
return true;
}
return false;
}
}
这题复习了HashMap对象的定义,getOrDefault(),equal()方法.
349. 两个数组的交集 - 力扣(LeetCode)
class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
HashSet<Integer> set1 = new HashSet<>();
HashSet<Integer> result = new HashSet<>();
for (int i : nums1) {
set1.add(i);
}
for (int i : nums2) {
if (set1.contains(i)) {
result.add(i);
}
}
int[] output = new int[result.size()];
int count = 0;
for (int i : result) {
output[count++] = i;
}
return output;
}
}
这题复习了HashSet对象的定义,add(),contais()方法.
202. 快乐数 - 力扣(LeetCode)
class Solution {
public boolean isHappy(int n) {
HashSet<Integer> set = new HashSet<>();
while (n != 1) {
int sum = 0;
while (n > 0) {
int digital = n % 10;
sum += digital * digital;
n /= 10;
}
n = sum;
if (set.contains(n)) {
return false;
}
set.add(n);
}
return true;
}
}
这里计算每一个位数上的平方的和是我所没想到的,感觉很妙.