Skip to content

Commit f820b01

Browse files
authored
Merge branch 'youngyangyang04:master' into master
2 parents e273f9a + f0db060 commit f820b01

File tree

251 files changed

+24351
-7537
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

251 files changed

+24351
-7537
lines changed

.DS_Store

6 KB
Binary file not shown.

README.md

Lines changed: 181 additions & 217 deletions
Large diffs are not rendered by default.

pics/网站星球宣传海报.jpg

280 KB
Loading

pics/训练营.png

994 KB
Loading

problems/0001.两数之和.md

Lines changed: 177 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<p align="center">
2-
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
3-
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210924105952.png" width="1000"/>
2+
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
3+
<img src="../pics/训练营.png" width="1000"/>
44
</a>
55
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
66

@@ -24,15 +24,26 @@
2424

2525
## 思路
2626

27-
很明显暴力的解法是两层for循环查找,时间复杂度是$O(n^2)$。
27+
建议看一下我录的这期视频:[梦开始的地方,Leetcode:1.两数之和](https://www.bilibili.com/video/BV1aT41177mK),结合本题解来学习,事半功倍。
28+
29+
很明显暴力的解法是两层for循环查找,时间复杂度是O(n^2)。
2830

2931
建议大家做这道题目之前,先做一下这两道
3032
* [242. 有效的字母异位词](https://www.programmercarl.com/0242.有效的字母异位词.html)
3133
* [349. 两个数组的交集](https://www.programmercarl.com/0349.两个数组的交集.html)
3234

3335
[242. 有效的字母异位词](https://www.programmercarl.com/0242.有效的字母异位词.html) 这道题目是用数组作为哈希表来解决哈希问题,[349. 两个数组的交集](https://www.programmercarl.com/0349.两个数组的交集.html)这道题目是通过set作为哈希表来解决哈希问题。
3436

35-
本题呢,则要使用map,那么来看一下使用数组和set来做哈希法的局限。
37+
38+
首先我在强调一下 **什么时候使用哈希法**,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。
39+
40+
本题呢,我就需要一个集合来存放我们遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
41+
42+
那么我们就应该想到使用哈希法了。
43+
44+
因为本地,我们不仅要知道元素有没有遍历过,还有知道这个元素对应的下标,**需要使用 key value结构来存放,key来存元素,value来存下标,那么使用map正合适**
45+
46+
再来看一下使用数组和set来做哈希法的局限。
3647

3748
* 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
3849
* set是一个集合,里面放的元素只能是一个key,而两数之和这道题目,不仅要判断y是否存在而且还要记录y的下标位置,因为要返回x 和 y的下标。所以set 也不能用。
@@ -43,20 +54,39 @@ C++中map,有三种类型:
4354

4455
|映射 |底层实现 | 是否有序 |数值是否可以重复 | 能否更改数值|查询效率 |增删效率|
4556
|---|---| --- |---| --- | --- | ---|
46-
|std::map |红黑树 |key有序 |key不可重复 |key不可修改 | $O(\log n)$|$O(\log n)$ |
47-
|std::multimap | 红黑树|key有序 | key可重复 | key不可修改|$O(\log n)$ |$O(\log n)$ |
48-
|std::unordered_map |哈希表 | key无序 |key不可重复 |key不可修改 |$O(1)$ | $O(1)$|
57+
|std::map |红黑树 |key有序 |key不可重复 |key不可修改 | O(log n)|O(log n) |
58+
|std::multimap | 红黑树|key有序 | key可重复 | key不可修改|O(log n) |O(log n) |
59+
|std::unordered_map |哈希表 | key无序 |key不可重复 |key不可修改 |O(1) | O(1)|
4960

5061
std::unordered_map 底层实现为哈希表,std::map 和std::multimap 的底层实现是红黑树。
5162

5263
同理,std::map 和std::multimap 的key也是有序的(这个问题也经常作为面试题,考察对语言容器底层的理解)。 更多哈希表的理论知识请看[关于哈希表,你该了解这些!](https://www.programmercarl.com/哈希表理论基础.html)
5364

54-
**这道题目中并不需要key有序,选择std::unordered_map 效率更高!**
65+
**这道题目中并不需要key有序,选择std::unordered_map 效率更高!** 使用其他语言的录友注意了解一下自己所用语言的数据结构就行。
66+
67+
接下来需要明确两点:
68+
69+
* **map用来做什么**
70+
* **map中key和value分别表示什么**
71+
72+
map目的用来存放我们访问过的元素,因为遍历数组的时候,需要记录我们之前遍历过哪些元素和对应的下标,这样才能找到与当前元素相匹配的(也就是相加等于target)
73+
74+
接下来是map中key和value分别表示什么。
75+
76+
这道题 我们需要 给出一个元素,判断这个元素是否出现过,如果出现过,返回这个元素的下标。
77+
78+
那么判断元素是否出现,这个元素就要作为key,所以数组中的元素作为key,有key对应的就是value,value用来存下标。
5579

56-
解题思路动画如下:
80+
所以 map中的存储结构为 {key:数据元素,value:数组元素对应的下标}。
5781

58-
![](https://code-thinking.cdn.bcebos.com/gifs/1.两数之和.gif)
82+
在遍历数组的时候,只需要向map去查询是否有和目前遍历元素匹配的数值,如果有,就找到的匹配对,如果没有,就把目前遍历的元素放进map中,因为map存放的就是我们访问过的元素。
5983

84+
过程如下:
85+
86+
![过程一](https://code-thinking-1253855093.file.myqcloud.com/pics/20220711202638.png)
87+
88+
89+
![过程二](https://code-thinking-1253855093.file.myqcloud.com/pics/20230220223536.png)
6090

6191
C++代码:
6292

@@ -66,18 +96,34 @@ public:
6696
vector<int> twoSum(vector<int>& nums, int target) {
6797
std::unordered_map <int,int> map;
6898
for(int i = 0; i < nums.size(); i++) {
69-
auto iter = map.find(target - nums[i]);
99+
// 遍历当前元素,并在map中寻找是否有匹配的key
100+
auto iter = map.find(target - nums[i]);
70101
if(iter != map.end()) {
71102
return {iter->second, i};
72103
}
73-
map.insert(pair<int, int>(nums[i], i));
104+
// 如果没找到匹配对,就把访问过的元素和下标加入到map中
105+
map.insert(pair<int, int>(nums[i], i));
74106
}
75107
return {};
76108
}
77109
};
78110
```
79111
112+
* 时间复杂度: O(n)
113+
* 空间复杂度: O(n)
114+
115+
## 总结
116+
117+
本题其实有四个重点:
118+
119+
* 为什么会想到用哈希表
120+
* 哈希表为什么用map
121+
* 本题map是用来存什么的
122+
* map中的key和value用来存什么的
80123
124+
把这四点想清楚了,本题才算是理解透彻了。
125+
126+
很多录友把这道题目 通过了,但都没想清楚map是用来做什么的,以至于对代码的理解其实是 一知半解的。
81127
82128
83129
## 其他语言版本
@@ -92,12 +138,13 @@ public int[] twoSum(int[] nums, int target) {
92138
}
93139
Map<Integer, Integer> map = new HashMap<>();
94140
for(int i = 0; i < nums.length; i++){
95-
int temp = target - nums[i];
141+
int temp = target - nums[i]; // 遍历当前元素,并在map中寻找是否有匹配的key
96142
if(map.containsKey(temp)){
97143
res[1] = i;
98144
res[0] = map.get(temp);
145+
break;
99146
}
100-
map.put(nums[i], i);
147+
map.put(nums[i], i); // 如果没找到匹配对,就把访问过的元素和下标加入到map中
101148
}
102149
return res;
103150
}
@@ -110,30 +157,17 @@ class Solution:
110157
def twoSum(self, nums: List[int], target: int) -> List[int]:
111158
records = dict()
112159

113-
# 用枚举更方便,就不需要通过索引再去取当前位置的值
114-
for idx, val in enumerate(nums):
115-
if target - val not in records:
116-
records[val] = idx
117-
else:
118-
return [records[target - val], idx] # 如果存在就返回字典记录索引和当前索引
119-
```
120-
121-
Python (v2):
122-
123-
```python
124-
class Solution:
125-
def twoSum(self, nums: List[int], target: int) -> List[int]:
126-
rec = {}
127-
for i in range(len(nums)):
128-
rest = target - nums[i]
129-
# Use get to get the index of the data, making use of one of the dictionary properties.
130-
if rec.get(rest, None) is not None: return [rec[rest], i]
131-
rec[nums[i]] = i
160+
for index, value in enumerate(nums):
161+
if target - value in records: # 遍历当前元素,并在map中寻找是否有匹配的key
162+
return [records[target- value], index]
163+
records[value] = index # 遍历当前元素,并在map中寻找是否有匹配的key
164+
return []
132165
```
133166

134167
Go:
135168

136169
```go
170+
// 暴力解法
137171
func twoSum(nums []int, target int) []int {
138172
for k1, _ := range nums {
139173
for k2 := k1 + 1; k2 < len(nums); k2++ {
@@ -188,11 +222,11 @@ Javascript
188222
```javascript
189223
var twoSum = function (nums, target) {
190224
let hash = {};
191-
for (let i = 0; i < nums.length; i++) {
225+
for (let i = 0; i < nums.length; i++) { // 遍历当前元素,并在map中寻找是否有匹配的key
192226
if (hash[target - nums[i]] !== undefined) {
193227
return [i, hash[target - nums[i]]];
194228
}
195-
hash[nums[i]] = i;
229+
hash[nums[i]] = i; // 如果没找到匹配对,就把访问过的元素和下标加入到map中
196230
}
197231
return [];
198232
};
@@ -221,13 +255,15 @@ php
221255
```php
222256
function twoSum(array $nums, int $target): array
223257
{
224-
for ($i = 0; $i < count($nums);$i++) {
225-
// 计算剩下的数
226-
$residue = $target - $nums[$i];
227-
// 匹配的index,有则返回index, 无则返回false
228-
$match_index = array_search($residue, $nums);
229-
if ($match_index !== false && $match_index != $i) {
230-
return array($i, $match_index);
258+
$map = [];
259+
foreach($nums as $i => $num) {
260+
if (isset($map[$target - $num])) {
261+
return [
262+
$i,
263+
$map[$target - $num]
264+
];
265+
} else {
266+
$map[$num] = $i;
231267
}
232268
}
233269
return [];
@@ -250,30 +286,6 @@ func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
250286
}
251287
```
252288

253-
PHP:
254-
```php
255-
class Solution {
256-
/**
257-
* @param Integer[] $nums
258-
* @param Integer $target
259-
* @return Integer[]
260-
*/
261-
function twoSum($nums, $target) {
262-
if (count($nums) == 0) {
263-
return [];
264-
}
265-
$table = [];
266-
for ($i = 0; $i < count($nums); $i++) {
267-
$temp = $target - $nums[$i];
268-
if (isset($table[$temp])) {
269-
return [$table[$temp], $i];
270-
}
271-
$table[$nums[$i]] = $i;
272-
}
273-
return [];
274-
}
275-
}
276-
```
277289

278290
Scala:
279291
```scala
@@ -317,6 +329,103 @@ public class Solution {
317329
}
318330
```
319331

332+
Dart:
333+
```dart
334+
List<int> twoSum(List<int> nums, int target) {
335+
var tmp = [];
336+
for (var i = 0; i < nums.length; i++) {
337+
var rest = target - nums[i];
338+
if(tmp.contains(rest)){
339+
return [tmp.indexOf(rest), i];
340+
}
341+
tmp.add(nums[i]);
342+
}
343+
return [0 , 0];
344+
}
345+
```
346+
347+
C:
348+
```c
349+
350+
351+
/**
352+
* Note: The returned array must be malloced, assume caller calls free().
353+
*/
354+
355+
// leetcode 支持 ut_hash 函式庫
356+
357+
typedef struct {
358+
int key;
359+
int value;
360+
UT_hash_handle hh; // make this structure hashable
361+
} map;
362+
363+
map* hashMap = NULL;
364+
365+
void hashMapAdd(int key, int value){
366+
map* s;
367+
// key already in the hash?
368+
HASH_FIND_INT(hashMap, &key, s);
369+
if(s == NULL){
370+
s = (map*)malloc(sizeof(map));
371+
s -> key = key;
372+
HASH_ADD_INT(hashMap, key, s);
373+
}
374+
s -> value = value;
375+
}
376+
377+
map* hashMapFind(int key){
378+
map* s;
379+
// *s: output pointer
380+
HASH_FIND_INT(hashMap, &key, s);
381+
return s;
382+
}
383+
384+
void hashMapCleanup(){
385+
map* cur, *tmp;
386+
HASH_ITER(hh, hashMap, cur, tmp){
387+
HASH_DEL(hashMap, cur);
388+
free(cur);
389+
}
390+
}
391+
392+
void hashPrint(){
393+
map* s;
394+
for(s = hashMap; s != NULL; s=(map*)(s -> hh.next)){
395+
printf("key %d, value %d\n", s -> key, s -> value);
396+
}
397+
}
398+
399+
400+
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
401+
int i, *ans;
402+
// hash find result
403+
map* hashMapRes;
404+
hashMap = NULL;
405+
ans = malloc(sizeof(int) * 2);
406+
407+
for(i = 0; i < numsSize; i++){
408+
// key 代表 nums[i] 的值,value 代表所在 index;
409+
hashMapAdd(nums[i], i);
410+
}
411+
412+
hashPrint();
320413

321-
-----------------------
322-
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
414+
for(i = 0; i < numsSize; i++){
415+
hashMapRes = hashMapFind(target - nums[i]);
416+
if(hashMapRes && hashMapRes -> value != i){
417+
ans[0] = i;
418+
ans[1] = hashMapRes -> value ;
419+
*returnSize = 2;
420+
return ans;
421+
}
422+
}
423+
424+
hashMapCleanup();
425+
return NULL;
426+
}
427+
```
428+
<p align="center">
429+
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
430+
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
431+
</a>

0 commit comments

Comments
 (0)