返回 LeetCode 刷题
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 字母异位词分组
Rendered Preview

哈希表(Hash Table)笔记

  1. 前提条件

之前学过的查找:顺序查找

数组: array
[8, 3, 5, 10, 7]

找:
10

需要:
8

3

5

10

比较四次。

时间复杂度:O(n)

然而二分查找

要求:必须有序

例如:[1,3,5,7,9]

查找:7

时间复杂度:O(log n)

有没有更快?

希望:一下找到

于是有:哈希表

  1. 核心概念

什么是哈希

例如:

学号

宿舍号

或者:

QQ号

用户信息

例如:

20260001

张三

我们希望:

输入key

直接找到value

于是:

key

哈希函数

数组下标

  1. 哈希函数

例如:

key = 123

哈希函数:

hash = key % 10;

得到:

3

存放:

table[3]

查找:

123

123 % 10

3

直接访问table[3]

时间复杂度:O(1)理想情况。

  1. 哈希表结构

本质:数组

例如:int table[10];

存:11

位置:

11 % 10 = 1

放:

table[1] = 11;

  1. 哈希冲突

最重要概念。

例如:

11 % 10 = 1

21 % 10 = 1

发现:两个元素

对应同一个位置

这就叫:哈希冲突(Hash Collision)

  1. 冲突解决方法

方法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

  1. 哈希表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

  1. 查找
    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;
    }

  2. 删除

思路和链表一样。

找到前驱

修改next

  1. 哈希表复杂度

理想情况:

插入 O(1)

查找 O(1)

删除 O(1)

极端情况:全部冲突

变成:链表

时间复杂度:O(n)

  1. LeetCode中的哈希思想

最经典:两数之和

1题

暴力:

for
for

时间:

O(n²)

哈希:边遍历,边存哈希表

例如:

nums=[2,7,11,15]

target=9

遍历:2
需要:7

查哈希:没有

存:2

遍历:7

需要:2

发现:哈希表里有

直接返回。

复杂度:O(n)

  1. 易错点
    哈希表不是排序

例如:

8

2

10

哈希表里可能:

2

10

8

没有顺序。

哈希冲突一定存在

不可能完全避免。

只能:减少

哈希函数要简单

常见:key % size
不要写太复杂。

  1. 题型总结
    类型1

查找是否存在

例如:

1 两数之和

217 存在重复元素

关键词:

是否存在

是否出现过

想到:

哈希表

类型2

统计次数

例如:

169 多数元素

347 前K个高频元素

关键词:

频率

次数

想到:哈希表

类型3

字符统计

例如:

242 有效字母异位词

3 无重复字符最长子串

关键词:

字符出现次数

想到:哈希表

哈希表(Hash Table)

核心思想:空间换时间


key

哈希函数

数组下标


理想复杂度:

插入 O(1)

查找 O(1)

删除 O(1)


冲突:

多个key映射同一位置


解决:

  1. 拉链法(链地址法)

数组+链表

  1. 开放定址法

往后找空位


常见哈希函数:

key % size


LeetCode关键词:

是否存在

是否出现过

统计次数

频率

字符计数

字符串哈希(ASCII 256数组)

LeetCode 1 两数之和
LeetCode 217 存在重复元素
LeetCode 242 有效字母异位词
LeetCode 49 字母异位词分组