Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9d18d18

Browse files
authored
Merge branch 'youngyangyang04:master' into master
2 parents 88182ed + 79b2453 commit 9d18d18

File tree

77 files changed

+500
-380
lines changed

Some content is hidden

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

77 files changed

+500
-380
lines changed

.DS_Store

-8 KB
Binary file not shown.

problems/0018.四数之和.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ class Solution(object):
216216

217217
# good thing about using python is you can use set to drop duplicates.
218218
ans = set()
219+
# ans = [] # save results by list()
219220
for i in range(len(nums)):
220221
for j in range(i + 1, len(nums)):
221222
for k in range(j + 1, len(nums)):
@@ -224,10 +225,16 @@ class Solution(object):
224225
# make sure no duplicates.
225226
count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val)
226227
if hashmap[val] > count:
227-
ans.add(tuple(sorted([nums[i], nums[j], nums[k], val])))
228-
else:
229-
continue
230-
return ans
228+
ans_tmp = tuple(sorted([nums[i], nums[j], nums[k], val]))
229+
ans.add(ans_tmp)
230+
# Avoiding duplication in list manner but it cause time complexity increases
231+
# if ans_tmp not in ans:
232+
# ans.append(ans_tmp)
233+
else:
234+
continue
235+
return list(ans)
236+
# if used list() to save results, just
237+
# return ans
231238

232239
```
233240

problems/0024.两两交换链表中的节点.md

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -254,32 +254,20 @@ TypeScript:
254254

255255
```typescript
256256
function swapPairs(head: ListNode | null): ListNode | null {
257-
/**
258-
* 初始状态:
259-
* curNode -> node1 -> node2 -> tmepNode
260-
* 转换过程:
261-
* curNode -> node2
262-
* curNode -> node2 -> node1
263-
* curNode -> node2 -> node1 -> tempNode
264-
* curNode = node1
265-
*/
266-
let retNode: ListNode | null = new ListNode(0, head),
267-
curNode: ListNode | null = retNode,
268-
node1: ListNode | null = null,
269-
node2: ListNode | null = null,
270-
tempNode: ListNode | null = null;
271-
272-
while (curNode && curNode.next && curNode.next.next) {
273-
node1 = curNode.next;
274-
node2 = curNode.next.next;
275-
tempNode = node2.next;
276-
curNode.next = node2;
277-
node2.next = node1;
278-
node1.next = tempNode;
279-
curNode = node1;
280-
}
281-
return retNode.next;
282-
};
257+
const dummyHead: ListNode = new ListNode(0, head);
258+
let cur: ListNode = dummyHead;
259+
while(cur.next !== null && cur.next.next !== null) {
260+
const tem: ListNode = cur.next;
261+
const tem1: ListNode = cur.next.next.next;
262+
263+
cur.next = cur.next.next; // step 1
264+
cur.next.next = tem; // step 2
265+
cur.next.next.next = tem1; // step 3
266+
267+
cur = cur.next.next;
268+
}
269+
return dummyHead.next;
270+
}
283271
```
284272

285273
Kotlin:

problems/0042.接雨水.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ public:
365365

366366
## 其他语言版本
367367

368-
Java:
368+
### Java:
369369

370370
双指针法
371371
```java
@@ -468,7 +468,7 @@ class Solution {
468468
}
469469
```
470470

471-
Python:
471+
### Python:
472472

473473
双指针法
474474
```python3
@@ -575,7 +575,7 @@ class Solution:
575575

576576
```
577577

578-
Go:
578+
### Go
579579

580580
```go
581581
func trap(height []int) int {
@@ -642,7 +642,7 @@ func min(a,b int)int{
642642

643643

644644

645-
JavaScript:
645+
### JavaScript:
646646

647647
```javascript
648648
//双指针
@@ -744,7 +744,7 @@ var trap = function(height) {
744744
};
745745
```
746746

747-
C:
747+
### C:
748748

749749
一种更简便的双指针方法:
750750

problems/0063.不同路径II.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,39 @@ public:
155155
* 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度
156156
* 空间复杂度:$O(n × m)$
157157
158+
159+
同样我们给出空间优化版本:
160+
```CPP
161+
class Solution {
162+
public:
163+
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
164+
if (obstacleGrid[0][0] == 1)
165+
return 0;
166+
vector<int> dp(obstacleGrid[0].size());
167+
for (int j = 0; j < dp.size(); ++j)
168+
if (obstacleGrid[0][j] == 1)
169+
dp[j] = 0;
170+
else if (j == 0)
171+
dp[j] = 1;
172+
else
173+
dp[j] = dp[j-1];
174+
175+
for (int i = 1; i < obstacleGrid.size(); ++i)
176+
for (int j = 0; j < dp.size(); ++j){
177+
if (obstacleGrid[i][j] == 1)
178+
dp[j] = 0;
179+
else if (j != 0)
180+
dp[j] = dp[j] + dp[j-1];
181+
}
182+
return dp.back();
183+
}
184+
};
185+
```
186+
187+
* 时间复杂度:$O(n × m)$,n、m 分别为obstacleGrid 长度和宽度
188+
* 空间复杂度:$O(m)$
189+
190+
158191
## 总结
159192

160193
本题是[62.不同路径](https://programmercarl.com/0062.不同路径.html)的障碍版,整体思路大体一致。

problems/0077.组合.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -423,8 +423,8 @@ class Solution:
423423
if len(path) == k:
424424
res.append(path[:])
425425
return
426-
for i in range(startIndex,n - (k - len(path)) + 2): #优化的地方
427-
path.append(i) #处理节点
426+
for i in range(startIndex,n-(k-len(path))+2): #优化的地方
427+
path.append(i) #处理节点
428428
backtrack(n,k,i+1) #递归
429429
path.pop() #回溯,撤销处理的节点
430430
backtrack(n,k,1)

problems/0116.填充每个节点的下一个右侧节点指针.md

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,52 @@ class Solution:
211211
return root
212212
```
213213
## Go
214-
215214
```go
216-
215+
// 迭代法
216+
func connect(root *Node) *Node {
217+
if root == nil {
218+
return root
219+
}
220+
stack := make([]*Node, 0)
221+
stack = append(stack, root)
222+
for len(stack) > 0 {
223+
n := len(stack) // 记录当前层节点个数
224+
for i := 0; i < n; i++ {
225+
node := stack[0] // 依次弹出节点
226+
stack = stack[1:]
227+
if i == n - 1 { // 如果是这层最右的节点,next指向nil
228+
node.Next = nil
229+
} else {
230+
node.Next = stack[0] // 如果不是最右的节点,next指向右边的节点
231+
}
232+
if node.Left != nil { // 如果存在左子节点,放入栈中
233+
stack = append(stack, node.Left)
234+
}
235+
if node.Right != nil { // 如果存在右子节点,放入栈中
236+
stack = append(stack, node.Right)
237+
}
238+
}
239+
}
240+
return root
241+
}
242+
```
243+
```go
244+
// 常量级额外空间,使用next
245+
func connect(root *Node) *Node {
246+
if root == nil {
247+
return root
248+
}
249+
for cur := root; cur.Left != nil; cur = cur.Left { // 遍历每层最左边的节点
250+
for node := cur; node != nil; node = node.Next { // 当前层从左到右遍历
251+
node.Left.Next = node.Right // 左子节点next指向右子节点
252+
if node.Next != nil { //如果node next有值,右子节点指向next节点的左子节点
253+
node.Right.Next = node.Next.Left
254+
}
255+
256+
}
257+
}
258+
return root
259+
}
217260
```
218261

219262
## JavaScript

problems/0139.单词拆分.md

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -250,30 +250,34 @@ class Solution {
250250

251251
// 回溯法+记忆化
252252
class Solution {
253+
private Set<String> set;
254+
private int[] memo;
253255
public boolean wordBreak(String s, List<String> wordDict) {
254-
Set<String> wordDictSet = new HashSet(wordDict);
255-
int[] memory = new int[s.length()];
256-
return backTrack(s, wordDictSet, 0, memory);
256+
memo = new int[s.length()];
257+
set = new HashSet<>(wordDict);
258+
return backtracking(s, 0);
257259
}
258-
259-
public boolean backTrack(String s, Set<String> wordDictSet, int startIndex, int[] memory) {
260-
// 结束条件
261-
if (startIndex >= s.length()) {
260+
261+
public boolean backtracking(String s, int startIndex) {
262+
// System.out.println(startIndex);
263+
if (startIndex == s.length()) {
262264
return true;
263265
}
264-
if (memory[startIndex] != 0) {
265-
// 此处认为:memory[i] = 1 表示可以拼出i 及以后的字符子串, memory[i] = -1 表示不能
266-
return memory[startIndex] == 1 ? true : false;
266+
if (memo[startIndex] == -1) {
267+
return false;
267268
}
268-
for (int i = startIndex; i < s.length(); ++i) {
269-
// 处理 递归 回溯 循环不变量:[startIndex, i + 1)
270-
String word = s.substring(startIndex, i + 1);
271-
if (wordDictSet.contains(word) && backTrack(s, wordDictSet, i + 1, memory)) {
272-
memory[startIndex] = 1;
273-
return true;
269+
270+
for (int i = startIndex; i < s.length(); i++) {
271+
String sub = s.substring(startIndex, i + 1);
272+
// 拆分出来的单词无法匹配
273+
if (!set.contains(sub)) {
274+
continue;
274275
}
276+
boolean res = backtracking(s, i + 1);
277+
if (res) return true;
275278
}
276-
memory[startIndex] = -1;
279+
// 这里是关键,找遍了startIndex~s.length()也没能完全匹配,标记从startIndex开始不能找到
280+
memo[startIndex] = -1;
277281
return false;
278282
}
279283
}

problems/0203.移除链表元素.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ function removeElements(head: ListNode | null, val: number): ListNode | null {
324324
head = head.next;
325325
}
326326
if (head === null) return head;
327-
let pre: ListNode = head, cur: ListNode = head.next;
327+
let pre: ListNode = head, cur: ListNode | null = head.next;
328328
// 删除非头部节点
329329
while (cur) {
330330
if (cur.val === val) {
@@ -342,14 +342,14 @@ function removeElements(head: ListNode | null, val: number): ListNode | null {
342342

343343
```typescript
344344
function removeElements(head: ListNode | null, val: number): ListNode | null {
345-
head = new ListNode(0, head);
346-
let pre: ListNode = head, cur: ListNode = head.next;
345+
let dummyHead = new ListNode(0, head);
346+
let pre: ListNode = dummyHead, cur: ListNode | null = dummyHead.next;
347347
// 删除非头部节点
348348
while (cur) {
349349
if (cur.val === val) {
350350
pre.next = cur.next;
351351
} else {
352-
pre = pre.next;
352+
pre = cur;
353353
}
354354
cur = cur.next;
355355
}

problems/0235.二叉搜索树的最近公共祖先.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,39 @@ var lowestCommonAncestor = function(root, p, q) {
350350
};
351351
```
352352

353+
## TypeScript
354+
355+
> 递归法:
356+
357+
```typescript
358+
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
359+
if (root.val > p.val && root.val > q.val)
360+
return lowestCommonAncestor(root.left, p, q);
361+
if (root.val < p.val && root.val < q.val)
362+
return lowestCommonAncestor(root.right, p, q);
363+
return root;
364+
};
365+
```
366+
367+
> 迭代法:
368+
369+
```typescript
370+
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
371+
while (root !== null) {
372+
if (root.val > p.val && root.val > q.val) {
373+
root = root.left;
374+
} else if (root.val < p.val && root.val < q.val) {
375+
root = root.right;
376+
} else {
377+
return root;
378+
};
379+
};
380+
return null;
381+
};
382+
```
383+
384+
385+
353386

354387
-----------------------
355388
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

problems/0236.二叉树的最近公共祖先.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,13 @@
4545

4646
接下来就看如何判断一个节点是节点q和节点p的公共公共祖先呢。
4747

48-
**如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。**
48+
**首先最容易想到的一个情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。**
4949

50-
使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现如何这个条件的节点,就是最近公共节点了。
50+
**但是很多人容易忽略一个情况,就是节点本身p(q),它拥有一个子孙节点q(p)。**
51+
52+
使用后序遍历,回溯的过程,就是从低向上遍历节点,一旦发现满足第一种情况的节点,就是最近公共节点了。
53+
54+
**但是如果p或者q本身就是最近公共祖先呢?其实只需要找到一个节点是p或者q的时候,直接返回当前节点,无需继续递归子树。如果接下来的遍历中找到了后继节点满足第一种情况则修改返回值为后继节点,否则,继续返回已找到的节点即可。为什么满足第一种情况的节点一定是p或q的后继节点呢?大家可以仔细思考一下。**
5155

5256
递归三部曲:
5357

problems/0309.最佳买卖股票时机含冷冻期.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,24 @@ const maxProfit = (prices) => {
284284
};
285285
```
286286

287+
```javascript
288+
// 一维数组空间优化
289+
const maxProfit = (prices) => {
290+
const n = prices.length
291+
const dp = new Array(4).fill(0)
292+
dp[0] = -prices[0]
293+
for (let i = 1; i < n; i ++) {
294+
const temp = dp[0] // 缓存上一次的状态
295+
const temp1 = dp[2]
296+
dp[0] = Math.max(dp[0], Math.max(dp[3] - prices[i], dp[1] - prices[i])) // 持有状态
297+
dp[1] = Math.max(dp[1], dp[3]) // 今天不操作且不持有股票
298+
dp[2] = temp + prices[i] // 今天卖出股票
299+
dp[3] = temp1 // 冷冻期
300+
}
301+
return Math.max(...dp)
302+
};
303+
```
304+
287305

288306
-----------------------
289307
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

0 commit comments

Comments
 (0)