1哈希表(Hash Table)笔记
21. 前提条件
3
4之前学过的查找:顺序查找
5
6数组: array
7[8, 3, 5, 10, 7]
8
9找:
1010
11
12需要:
138
14
153
16
175
18
1910
20
21比较四次。
22
23时间复杂度:O(n)
24
25然而二分查找
26
27要求:必须有序
28
29例如:[1,3,5,7,9]
30
31查找:7
32
33时间复杂度:O(log n)
34
35有没有更快?
36
37希望:一下找到
38
39于是有:哈希表
40
412. 核心概念
42
43什么是哈希
44
45例如:
46
47学号
48
49↓
50
51宿舍号
52
53或者:
54
55QQ号
56
57↓
58
59用户信息
60
61例如:
62
6320260001
64
65↓
66
67张三
68
69我们希望:
70
71输入key
72
73直接找到value
74
75于是:
76
77key
78
79↓
80
81哈希函数
82
83↓
84
85数组下标
86
873. 哈希函数
88
89例如:
90
91key = 123
92
93哈希函数:
94
95hash = key % 10;
96
97得到:
98
993
100
101存放:
102
103table[3]
104
105查找:
106
107123
108
109↓
110
111123 % 10
112
113↓
114
1153
116
117↓
118
119直接访问table[3]
120
121时间复杂度:O(1)理想情况。
122
1234. 哈希表结构
124
125本质:数组
126
127例如:int table[10];
128
129存:11
130
131位置:
132
13311 % 10 = 1
134
135放:
136
137table[1] = 11;
138
1395. 哈希冲突
140
141最重要概念。
142
143例如:
144
14511 % 10 = 1
146
14721 % 10 = 1
148
149发现:两个元素
150
151对应同一个位置
152
153这就叫:哈希冲突(Hash Collision)
154
1556. 冲突解决方法
156
157方法1:拉链法
158
159又叫:链地址法
160
161例如:
162
16311
164
16521
166
16731
168
169都映射到:1
170
171存:table[1]
172
173↓
174
17511 -> 21 -> 31
176
177即:
178
179数组 + 链表
180
181图:
182
1830
184
1851 -> 11 -> 21 -> 31
186
1872
188
1893
190
191优点:
192简单
193
194常用
195
196LeetCode里的哈希表基本都这么实现。
197
198方法2:开放定址法
199
200发生冲突:
201
202往后找空位
203
204例如:
205
20611
207
208↓
209
2101
211
212放:table[1]
213
214再插入:
215
21621
217
218↓
219
2201
221
222发现:
223
224table[1]
225
226被占了。
227
228往后:
229
230table[2]
231
232空。
233
234放进去。
235
236最终:
237
2381:11
239
2402:21
241
2427. 哈希表ADT
243
244结构体
245链地址法:
246
247struct Node
248{
249 int key;
250
251 struct Node* next;
252};
253
254struct HashTable
255{
256 struct Node* table[100];
257};
258
259哈希函数
260int hash(int key)
261{
262 return key % 100;
263}
264
265插入
266void insert(
267 struct HashTable* h,
268 int key)
269{
270 int index = hash(key);
271
272 struct Node* node =
273 malloc(sizeof(struct Node));
274
275 node->key = key;
276
277 node->next =
278 h->table[index];
279
280 h->table[index] = node;
281}
282
283理解:头插法。
284
285例如:
286
28711
288
28921
290
29131
292
293结果:
294
29531 -> 21 -> 11
296
2978. 查找
298bool search(
299 struct HashTable* h,
300 int key)
301{
302 int index = hash(key);
303
304 struct Node* cur =
305 h->table[index];
306
307 while(cur != NULL)
308 {
309 if(cur->key == key)
310 {
311 return true;
312 }
313
314 cur = cur->next;
315 }
316
317 return false;
318}
319
3209. 删除
321
322思路和链表一样。
323
324找到前驱
325
326修改next
327
328
32910. 哈希表复杂度
330
331理想情况:
332
333插入 O(1)
334
335查找 O(1)
336
337删除 O(1)
338
339极端情况:全部冲突
340
341变成:链表
342
343时间复杂度:O(n)
344
34511. LeetCode中的哈希思想
346
347最经典:两数之和
348
3491题
350
351暴力:
352
353for
354 for
355
356时间:
357
358O(n²)
359
360哈希:边遍历,边存哈希表
361
362例如:
363
364nums=[2,7,11,15]
365
366target=9
367
368遍历:2
369需要:7
370
371查哈希:没有
372
373存:2
374
375遍历:7
376
377需要:2
378
379发现:哈希表里有
380
381直接返回。
382
383复杂度:O(n)
384
38512. 易错点
386哈希表不是排序
387
388例如:
389
3908
391
3922
393
39410
395
396哈希表里可能:
397
3982
399
40010
401
4028
403
404没有顺序。
405
406哈希冲突一定存在
407
408不可能完全避免。
409
410只能:减少
411
412哈希函数要简单
413
414常见:key % size
415不要写太复杂。
416
41713. 题型总结
418类型1
419
420查找是否存在
421
422例如:
423
4241 两数之和
425
426217 存在重复元素
427
428关键词:
429
430是否存在
431
432是否出现过
433
434想到:
435
436哈希表
437
438类型2
439
440统计次数
441
442例如:
443
444169 多数元素
445
446347 前K个高频元素
447
448关键词:
449
450频率
451
452次数
453
454想到:哈希表
455
456类型3
457
458字符统计
459
460例如:
461
462242 有效字母异位词
463
4643 无重复字符最长子串
465
466关键词:
467
468字符出现次数
469
470想到:哈希表
471
472哈希表(Hash Table)
473
474核心思想:空间换时间
475
476--------------------------------
477
478key
479
480↓
481
482哈希函数
483
484↓
485
486数组下标
487
488--------------------------------
489
490理想复杂度:
491
492插入 O(1)
493
494查找 O(1)
495
496删除 O(1)
497
498--------------------------------
499
500冲突:
501
502多个key映射同一位置
503
504--------------------------------
505
506解决:
507
5081. 拉链法(链地址法)
509
510数组+链表
511
5122. 开放定址法
513
514往后找空位
515
516--------------------------------
517
518常见哈希函数:
519
520key % size
521
522--------------------------------
523
524LeetCode关键词:
525
526是否存在
527
528是否出现过
529
530统计次数
531
532频率
533
534字符计数
535
536↓
537
538字符串哈希(ASCII 256数组)
539↓
540LeetCode 1 两数之和
541LeetCode 217 存在重复元素
542LeetCode 242 有效字母异位词
543LeetCode 49 字母异位词分组
哈希表(Hash Table)笔记
- 前提条件
之前学过的查找:顺序查找
数组: array
[8, 3, 5, 10, 7]
找:
10
需要:
8
3
5
10
比较四次。
时间复杂度:O(n)
然而二分查找
要求:必须有序
例如:[1,3,5,7,9]
查找:7
时间复杂度:O(log n)
有没有更快?
希望:一下找到
于是有:哈希表
- 核心概念
什么是哈希
例如:
学号
↓
宿舍号
或者:
QQ号
↓
用户信息
例如:
20260001
↓
张三
我们希望:
输入key
直接找到value
于是:
key
↓
哈希函数
↓
数组下标
- 哈希函数
例如:
key = 123
哈希函数:
hash = key % 10;
得到:
3
存放:
table[3]
查找:
123
↓
123 % 10
↓
3
↓
直接访问table[3]
时间复杂度:O(1)理想情况。
- 哈希表结构
本质:数组
例如:int table[10];
存:11
位置:
11 % 10 = 1
放:
table[1] = 11;
- 哈希冲突
最重要概念。
例如:
11 % 10 = 1
21 % 10 = 1
发现:两个元素
对应同一个位置
这就叫:哈希冲突(Hash Collision)
- 冲突解决方法
方法1:拉链法
又叫:链地址法
例如:
11
21
31
都映射到:1
存:table[1]
↓
11 -> 21 -> 31
即:
数组 + 链表
图:
0
1 -> 11 -> 21 -> 31
2
3
优点:
简单
常用
LeetCode里的哈希表基本都这么实现。
方法2:开放定址法
发生冲突:
往后找空位
例如:
11
↓
1
放:table[1]
再插入:
21
↓
1
发现:
table[1]
被占了。
往后:
table[2]
空。
放进去。
最终:
1:11
2:21
- 哈希表ADT
结构体
链地址法:
struct Node
{
int key;
struct Node* next;
};
struct HashTable
{
struct Node* table[100];
};
哈希函数
int hash(int key)
{
return key % 100;
}
插入
void insert(
struct HashTable* h,
int key)
{
int index = hash(key);
struct Node* node =
malloc(sizeof(struct Node));
node->key = key;
node->next =
h->table[index];
h->table[index] = node;
}
理解:头插法。
例如:
11
21
31
结果:
31 -> 21 -> 11
-
查找
bool search(
struct HashTable* h,
int key)
{
int index = hash(key);
struct Node* cur =
h->table[index];
while(cur != NULL)
{
if(cur->key == key)
{
return true;
}
cur = cur->next;
}
return false;
}
-
删除
思路和链表一样。
找到前驱
修改next
- 哈希表复杂度
理想情况:
插入 O(1)
查找 O(1)
删除 O(1)
极端情况:全部冲突
变成:链表
时间复杂度:O(n)
- LeetCode中的哈希思想
最经典:两数之和
1题
暴力:
for
for
时间:
O(n²)
哈希:边遍历,边存哈希表
例如:
nums=[2,7,11,15]
target=9
遍历:2
需要:7
查哈希:没有
存:2
遍历:7
需要:2
发现:哈希表里有
直接返回。
复杂度:O(n)
- 易错点
哈希表不是排序
例如:
8
2
10
哈希表里可能:
2
10
8
没有顺序。
哈希冲突一定存在
不可能完全避免。
只能:减少
哈希函数要简单
常见:key % size
不要写太复杂。
- 题型总结
类型1
查找是否存在
例如:
1 两数之和
217 存在重复元素
关键词:
是否存在
是否出现过
想到:
哈希表
类型2
统计次数
例如:
169 多数元素
347 前K个高频元素
关键词:
频率
次数
想到:哈希表
类型3
字符统计
例如:
242 有效字母异位词
3 无重复字符最长子串
关键词:
字符出现次数
想到:哈希表
哈希表(Hash Table)
核心思想:空间换时间
key
↓
哈希函数
↓
数组下标
理想复杂度:
插入 O(1)
查找 O(1)
删除 O(1)
冲突:
多个key映射同一位置
解决:
- 拉链法(链地址法)
数组+链表
- 开放定址法
往后找空位
常见哈希函数:
key % size
LeetCode关键词:
是否存在
是否出现过
统计次数
频率
字符计数
↓
字符串哈希(ASCII 256数组)
↓
LeetCode 1 两数之和
LeetCode 217 存在重复元素
LeetCode 242 有效字母异位词
LeetCode 49 字母异位词分组