Skip to content

Commit dc3f73e

Browse files
authored
Merge branch 'youngyangyang04:master' into master
2 parents 5e960b4 + acf1a54 commit dc3f73e

37 files changed

+740
-308
lines changed

problems/0005.最长回文子串.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
# 5.最长回文子串
1212

13-
题目链接:https://leetcode-cn.com/problems/longest-palindromic-substring/
13+
[力扣题目链接](https://leetcode-cn.com/problems/longest-palindromic-substring/)
1414

1515
给你一个字符串 s,找到 s 中最长的回文子串。
1616

@@ -30,11 +30,11 @@
3030
示例 4:
3131
* 输入:s = "ac"
3232
* 输出:"a"
33-
 
33+
3434

3535
# 思路
3636

37-
本题和[647.回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw) 差不多是一样的,但647.回文子串更基本一点,建议可以先做647.回文子串
37+
本题和[647.回文子串](https://programmercarl.com/0647.回文子串.html) 差不多是一样的,但647.回文子串更基本一点,建议可以先做647.回文子串
3838

3939
## 暴力解法
4040

problems/0015.三数之和.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99

1010

11-
> 用哈希表解决了[两数之和](https://mp.weixin.qq.com/s/uVAtjOHSeqymV8FeQbliJQ),那么三数之和呢?
11+
> 用哈希表解决了[两数之和](https://programmercarl.com/0001.两数之和.html),那么三数之和呢?
1212
1313
# 第15题. 三数之和
1414

15-
https://leetcode-cn.com/problems/3sum/
15+
[力扣题目链接](https://leetcode-cn.com/problems/3sum/)
1616

1717
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
1818

@@ -37,7 +37,7 @@ https://leetcode-cn.com/problems/3sum/
3737

3838
两层for循环就可以确定 a 和b 的数值了,可以使用哈希法来确定 0-(a+b) 是否在 数组里出现过,其实这个思路是正确的,但是我们有一个非常棘手的问题,就是题目中说的不可以包含重复的三元组。
3939

40-
把符合条件的三元组放进vector中,然后在去去重,这样是非常费时的,很容易超时,也是这道题目通过率如此之低的根源所在。
40+
把符合条件的三元组放进vector中,然后再去重,这样是非常费时的,很容易超时,也是这道题目通过率如此之低的根源所在。
4141

4242
去重的过程不好处理,有很多小细节,如果在面试中很难想到位。
4343

@@ -95,11 +95,11 @@ public:
9595
9696
![15.三数之和](https://code-thinking.cdn.bcebos.com/gifs/15.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.gif)
9797
98-
拿这个nums数组来举例,首先将数组排序,然后有一层for循环,i从下表0的地方开始,同时定一个下表left 定义在i+1的位置上,定义下表right 在数组结尾的位置上。
98+
拿这个nums数组来举例,首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
9999
100100
依然还是在数组中找到 abc 使得a + b +c =0,我们这里相当于 a = nums[i] b = nums[left] c = nums[right]。
101101
102-
接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下表就应该向左移动,这样才能让三数之和小一些。
102+
接下来如何移动left 和right呢, 如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
103103
104104
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
105105
@@ -163,13 +163,13 @@ public:
163163
# 思考题
164164

165165

166-
既然三数之和可以使用双指针法,我们之前讲过的[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ),可不可以使用双指针法呢?
166+
既然三数之和可以使用双指针法,我们之前讲过的[1.两数之和](https://programmercarl.com/0001.两数之和.html),可不可以使用双指针法呢?
167167

168168
如果不能,题意如何更改就可以使用双指针法呢? **大家留言说出自己的想法吧!**
169169

170-
两数之和 就不能使用双指针法,因为[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)要求返回的是索引下表, 而双指针法一定要排序,一旦排序之后原数组的索引就被改变了。
170+
两数之和 就不能使用双指针法,因为[1.两数之和](https://programmercarl.com/0001.两数之和.html)要求返回的是索引下标, 而双指针法一定要排序,一旦排序之后原数组的索引就被改变了。
171171

172-
如果[1.两数之和](https://mp.weixin.qq.com/s/vaMsLnH-f7_9nEK4Cuu3KQ)要求返回的是数值的话,就可以使用双指针法了。
172+
如果[1.两数之和](https://programmercarl.com/0001.两数之和.html)要求返回的是数值的话,就可以使用双指针法了。
173173

174174

175175

problems/0017.电话号码的字母组合.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
# 17.电话号码的字母组合
1111

12-
题目链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
12+
[力扣题目链接](https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/)
1313

1414
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
1515

@@ -29,7 +29,7 @@
2929

3030
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环.......
3131

32-
大家应该感觉出和[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
32+
大家应该感觉出和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
3333

3434
理解本题后,要解决如下三个问题:
3535

@@ -58,7 +58,7 @@ const string letterMap[10] = {
5858

5959
## 回溯法来解决n个for循环的问题
6060

61-
对于回溯法还不了解的同学看这篇:[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)
61+
对于回溯法还不了解的同学看这篇:[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)
6262

6363

6464
例如:输入:"23",抽象为树形结构,如图所示:
@@ -75,7 +75,7 @@ const string letterMap[10] = {
7575

7676
再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。
7777

78-
注意这个index可不是 [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中的startIndex了。
78+
注意这个index可不是 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中的startIndex了。
7979

8080
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
8181

@@ -120,9 +120,9 @@ for (int i = 0; i < letters.size(); i++) {
120120
}
121121
```
122122

123-
**注意这里for循环,可不像是在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中从startIndex开始遍历的**
123+
**注意这里for循环,可不像是在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中从startIndex开始遍历的**
124124

125-
**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[216.组合总和III](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)都是是求同一个集合中的组合!**
125+
**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[77. 组合](https://programmercarl.com/0077.组合.html)[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)都是是求同一个集合中的组合!**
126126

127127

128128
注意:输入1 * #按键等等异常情况
@@ -134,7 +134,7 @@ for (int i = 0; i < letters.size(); i++) {
134134

135135
## C++代码
136136

137-
关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的回溯法模板,不难写出如下C++代码:
137+
关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的回溯法模板,不难写出如下C++代码:
138138

139139

140140
```c++
@@ -224,13 +224,13 @@ public:
224224
};
225225
```
226226

227-
我不建议把回溯藏在递归的参数里这种写法,很不直观,我在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)这篇文章中也深度分析了,回溯隐藏在了哪里。
227+
我不建议把回溯藏在递归的参数里这种写法,很不直观,我在[二叉树:以为使用了递归,其实还隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html)这篇文章中也深度分析了,回溯隐藏在了哪里。
228228

229229
所以大家可以按照版本一来写就可以了。
230230

231231
# 总结
232232

233-
本篇将题目的三个要点一一列出,并重点强调了和前面讲解过的[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[216.组合总和III](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)的区别,本题是多个集合求组合,所以在回溯的搜索过程中,都有一些细节需要注意的。
233+
本篇将题目的三个要点一一列出,并重点强调了和前面讲解过的[77. 组合](https://programmercarl.com/0077.组合.html)[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)的区别,本题是多个集合求组合,所以在回溯的搜索过程中,都有一些细节需要注意的。
234234

235235
其实本题不算难,但也处处是细节,大家还要自己亲自动手写一写。
236236

problems/0018.四数之和.md

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
# 第18题. 四数之和
1414

15-
https://leetcode-cn.com/problems/4sum/
15+
[力扣题目链接](https://leetcode-cn.com/problems/4sum/)
1616

1717
题意:给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
1818

@@ -31,37 +31,37 @@ https://leetcode-cn.com/problems/4sum/
3131

3232
# 思路
3333

34-
四数之和,和[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)是一个思路,都是使用双指针法, 基本解法就是在[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg) 的基础上再套一层for循环。
34+
四数之和,和[15.三数之和](https://programmercarl.com/0015.三数之和.html)是一个思路,都是使用双指针法, 基本解法就是在[15.三数之和](https://programmercarl.com/0015.三数之和.html) 的基础上再套一层for循环。
3535

3636
但是有一些细节需要注意,例如: 不要判断`nums[k] > target` 就返回了,三数之和 可以通过 `nums[i] > 0` 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。(大家亲自写代码就能感受出来)
3737

38-
[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)的双指针解法是一层for循环num[i]为确定值,然后循环内有left和right下表作为双指针,找到nums[i] + nums[left] + nums[right] == 0。
38+
[15.三数之和](https://programmercarl.com/0015.三数之和.html)的双指针解法是一层for循环num[i]为确定值,然后循环内有left和right下表作为双指针,找到nums[i] + nums[left] + nums[right] == 0。
3939

4040
四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下表作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况,三数之和的时间复杂度是O(n^2),四数之和的时间复杂度是O(n^3) 。
4141

4242
那么一样的道理,五数之和、六数之和等等都采用这种解法。
4343

44-
对于[15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)双指针法就是将原本暴力O(n^3)的解法,降为O(n^2)的解法,四数之和的双指针解法就是将原本暴力O(n^4)的解法,降为O(n^3)的解法。
44+
对于[15.三数之和](https://programmercarl.com/0015.三数之和.html)双指针法就是将原本暴力O(n^3)的解法,降为O(n^2)的解法,四数之和的双指针解法就是将原本暴力O(n^4)的解法,降为O(n^3)的解法。
4545

46-
之前我们讲过哈希表的经典题目:[454.四数相加II](https://mp.weixin.qq.com/s/12g_w6RzHuEpFts1pT6BWw),相对于本题简单很多,因为本题是要求在一个集合中找出四个数相加等于target,同时四元组不能重复。
46+
之前我们讲过哈希表的经典题目:[454.四数相加II](https://programmercarl.com/0454.四数相加II.html),相对于本题简单很多,因为本题是要求在一个集合中找出四个数相加等于target,同时四元组不能重复。
4747

48-
[454.四数相加II](https://mp.weixin.qq.com/s/12g_w6RzHuEpFts1pT6BWw)是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于本题还是简单了不少!
48+
[454.四数相加II](https://programmercarl.com/0454.四数相加II.html)是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于本题还是简单了不少!
4949

5050
我们来回顾一下,几道题目使用了双指针法。
5151

5252
双指针法将时间复杂度O(n^2)的解法优化为 O(n)的解法。也就是降一个数量级,题目如下:
5353

54-
* [27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)
55-
* [15.三数之和](https://mp.weixin.qq.com/s/QfTNEByq1YlNSXRKEumwHg)
56-
* [18.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)
54+
* [27.移除元素](https://programmercarl.com/0027.移除元素.html)
55+
* [15.三数之和](https://programmercarl.com/0015.三数之和.html)
56+
* [18.四数之和](https://programmercarl.com/0018.四数之和.html)
5757

5858

5959
操作链表:
6060

61-
* [206.反转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)
62-
* [19.删除链表的倒数第N个节点](https://mp.weixin.qq.com/s/gxu65X1343xW_sBrkTz0Eg)
63-
* [面试题 02.07. 链表相交](https://mp.weixin.qq.com/s/BhfFfaGvt9Zs7UmH4YehZw)
64-
* [142题.环形链表II](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)
61+
* [206.反转链表](https://programmercarl.com/0206.翻转链表.html)
62+
* [19.删除链表的倒数第N个节点](https://programmercarl.com/0019.删除链表的倒数第N个节点.html)
63+
* [面试题 02.07. 链表相交](https://programmercarl.com/面试题02.07.链表相交.html)
64+
* [142题.环形链表II](https://programmercarl.com/0142.环形链表II.html)
6565

6666
双指针法在字符串题目中还有很多应用,后面还会介绍到。
6767

@@ -167,7 +167,33 @@ class Solution {
167167

168168
Python:
169169
```python
170-
170+
# 双指针法
171+
class Solution:
172+
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
173+
174+
nums.sort()
175+
n = len(nums)
176+
res = []
177+
for i in range(n):
178+
if i > 0 and nums[i] == nums[i - 1]: continue
179+
for k in range(i+1, n):
180+
if k > i + 1 and nums[k] == nums[k-1]: continue
181+
p = k + 1
182+
q = n - 1
183+
184+
while p < q:
185+
if nums[i] + nums[k] + nums[p] + nums[q] > target: q -= 1
186+
elif nums[i] + nums[k] + nums[p] + nums[q] < target: p += 1
187+
else:
188+
res.append([nums[i], nums[k], nums[p], nums[q]])
189+
while p < q and nums[p] == nums[p + 1]: p += 1
190+
while p < q and nums[q] == nums[q - 1]: q -= 1
191+
p += 1
192+
q -= 1
193+
return res
194+
```
195+
```python
196+
# 哈希表法
171197
class Solution(object):
172198
def fourSum(self, nums, target):
173199
"""

problems/0019.删除链表的倒数第N个节点.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
## 19.删除链表的倒数第N个节点
1313

14-
题目链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
14+
[力扣题目链接](https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/)
1515

1616
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
1717

@@ -41,7 +41,7 @@
4141

4242
分为如下几步:
4343

44-
* 首先这里我推荐大家使用虚拟头结点,这样方面处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以看这篇: [链表:听说用虚拟头节点会方便很多?](https://mp.weixin.qq.com/s/L5aanfALdLEwVWGvyXPDqA)
44+
* 首先这里我推荐大家使用虚拟头结点,这样方面处理删除实际头结点的逻辑,如果虚拟头结点不清楚,可以看这篇: [链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
4545

4646
* 定义fast指针和slow指针,初始值为虚拟头结点,如图:
4747

@@ -204,6 +204,31 @@ fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
204204
}
205205
```
206206

207+
Swift:
208+
```swift
209+
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
210+
if head == nil {
211+
return nil
212+
}
213+
if n == 0 {
214+
return head
215+
}
216+
let dummyHead = ListNode(-1, head)
217+
var fast: ListNode? = dummyHead
218+
var slow: ListNode? = dummyHead
219+
// fast 前移 n
220+
for _ in 0 ..< n {
221+
fast = fast?.next
222+
}
223+
while fast?.next != nil {
224+
fast = fast?.next
225+
slow = slow?.next
226+
}
227+
slow?.next = slow?.next?.next
228+
return dummyHead.next
229+
}
230+
```
231+
207232
-----------------------
208233
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
209234
* B站视频:[代码随想录](https://space.bilibili.com/525438321)

problems/0020.有效的括号.md

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
1313
# 20. 有效的括号
1414

15-
https://leetcode-cn.com/problems/valid-parentheses/
15+
[力扣题目链接](https://leetcode-cn.com/problems/valid-parentheses/)
1616

1717
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
1818

@@ -162,18 +162,44 @@ class Solution {
162162

163163
Python:
164164
```python3
165+
# 方法一,仅使用栈,更省空间
165166
class Solution:
166167
def isValid(self, s: str) -> bool:
167-
stack = [] # 保存还未匹配的左括号
168-
mapping = {")": "(", "]": "[", "}": "{"}
169-
for i in s:
170-
if i in "([{": # 当前是左括号,则入栈
171-
stack.append(i)
172-
elif stack and stack[-1] == mapping[i]: # 当前是配对的右括号则出栈
168+
stack = []
169+
170+
for item in s:
171+
if item == '(':
172+
stack.append(')')
173+
elif item == '[':
174+
stack.append(']')
175+
elif item == '{':
176+
stack.append('}')
177+
elif not stack or stack[-1] != item:
178+
return False
179+
else:
173180
stack.pop()
174-
else: # 不是匹配的右括号或者没有左括号与之匹配,则返回false
181+
182+
return True if not stack else False
183+
```
184+
185+
```python3
186+
# 方法二,使用字典
187+
class Solution:
188+
def isValid(self, s: str) -> bool:
189+
stack = []
190+
mapping = {
191+
'(': ')',
192+
'[': ']',
193+
'{': '}'
194+
}
195+
for item in s:
196+
if item in mapping.keys():
197+
stack.append(mapping[item])
198+
elif not stack or stack[-1] != item:
175199
return False
176-
return stack == [] # 最后必须正好把左括号匹配完
200+
else:
201+
stack.pop()
202+
return True if not stack else False
177203
```
178204

179205
Go:

0 commit comments

Comments
 (0)