Skip to content

Commit 6c32aaf

Browse files
author
lucifer
committed
2 parents fc8d6e1 + e3ee919 commit 6c32aaf

7 files changed

+187
-49
lines changed

problems/25.reverse-nodes-in-k-groups-cn.md

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ curr = temp;
6565
![reverse k nodes in linked list](../assets/problems/25.reverse-nodes-in-k-groups-2.PNG)
6666

6767

68-
>**NOTE**: 一般情况下对链表的操作,都有可能会引入一个新的`dummy node`,因为`head`有可能会改变。这里`head 从1->3`,
68+
>**NOTE**: 一般情况下对链表的操作,都有可能会引入一个新的`dummy node`,因为`head`有可能会改变。这里`head 从1->3`,
6969
`dummy (List(0)) `保持不变。
7070

7171
#### 复杂度分析
@@ -78,7 +78,7 @@ curr = temp;
7878
3. 对每一组进行翻转,更换起始和最后的位置
7979
4. 返回`dummy.next`.
8080

81-
## 代码 (`Java/Python3`)
81+
## 代码 (`Java/Python3/javascript`)
8282
*Java Code*
8383
```java
8484
class ReverseKGroupsLinkedList {
@@ -88,7 +88,7 @@ class ReverseKGroupsLinkedList {
8888
}
8989
ListNode dummy = new ListNode(0);
9090
dummy.next = head;
91-
91+
9292
ListNode start = dummy;
9393
ListNode end = head;
9494
int count = 0;
@@ -105,21 +105,21 @@ class ReverseKGroupsLinkedList {
105105
}
106106
return dummy.next;
107107
}
108-
109-
/**
108+
109+
/**
110110
* reverse linked list from range (start, end), return last node.
111-
* for example:
111+
* for example:
112112
* 0->1->2->3->4->5->6->7->8
113113
* | |
114114
* start end
115-
*
115+
*
116116
* After call start = reverse(start, end)
117-
*
117+
*
118118
* 0->3->2->1->4->5->6->7->8
119119
* | |
120120
* start end
121121
* first
122-
*
122+
*
123123
*/
124124
private ListNode reverse(ListNode start, ListNode end) {
125125
ListNode curr = start.next;
@@ -157,7 +157,7 @@ class Solution:
157157
else:
158158
end = end.next
159159
return dummy.next
160-
160+
161161
def reverse(self, start, end):
162162
prev, curr = start, start.next
163163
first = curr
@@ -168,7 +168,49 @@ class Solution:
168168
curr = temp
169169
start.next = prev
170170
first.next = curr
171-
return first
171+
return first
172+
```
173+
174+
*javascript code*
175+
```js
176+
/**
177+
* @param {ListNode} head
178+
* @param {number} k
179+
* @return {ListNode}
180+
*/
181+
var reverseKGroup = function(head, k) {
182+
// 标兵
183+
let dummy = new ListNode()
184+
dummy.next = head
185+
let [start, end] = [dummy, dummy.next]
186+
let count = 0
187+
while(end) {
188+
count++
189+
if (count % k === 0) {
190+
start = reverseList(start, end.next)
191+
end = start.next
192+
} else {
193+
end = end.next
194+
}
195+
}
196+
return dummy.next
197+
198+
// 翻转stat -> end的链表
199+
function reverseList(start, end) {
200+
let [pre, cur] = [start, start.next]
201+
const first = cur
202+
while(cur !== end) {
203+
let next = cur.next
204+
cur.next = pre
205+
pre = cur
206+
cur = next
207+
}
208+
start.next = pre
209+
first.next = cur
210+
return first
211+
}
212+
};
213+
172214
```
173215

174216
## 参考(References)
@@ -178,13 +220,13 @@ class Solution:
178220

179221
- 要求从后往前以`k`个为一组进行翻转。**(字节跳动(ByteDance)面试题)**
180222

181-
例子,`1->2->3->4->5->6->7->8, k = 3`,
182-
223+
例子,`1->2->3->4->5->6->7->8, k = 3`,
224+
183225
从后往前以`k=3`为一组,
184-
- `6->7->8` 为一组翻转为`8->7->6`
185-
- `3->4->5`为一组翻转为`5->4->3`.
226+
- `6->7->8` 为一组翻转为`8->7->6`
227+
- `3->4->5`为一组翻转为`5->4->3`.
186228
- `1->2`只有2个nodes少于`k=3`个,不翻转。
187-
229+
188230
最后返回: `1->2->5->4->3->8->7->6`
189231

190232
这里的思路跟从前往后以`k`个为一组进行翻转类似,可以进行预处理:

problems/283.move-zeroes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Minimize the total number of operations.
1818
```
1919
## 思路
2020

21-
如果题目没有要求 modify in-place 的话,我们可以先遍历一遍将包含 0 的和不包含 0 的存到两个数字
21+
如果题目没有要求 modify in-place 的话,我们可以先遍历一遍将包含 0 的和不包含 0 的存到两个数组
2222
然后拼接两个数组即可。 但是题目要求 modify in-place, 也就是不需要借助额外的存储空间,刚才的方法
2323
空间复杂度是 O(n).
2424

problems/32.longest-valid-parentheses.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,15 @@ s = '(())())'
4444
1. 第3点特征, 需要检查的字符是s[i-1]和s[i-2-dp[i-1]], 根据定义可知: i-1 >= dp[i-1], 但是i-2不一定大于dp[i-1], 因此, 需要检查越界;
4545
3. 第4点特征最容易遗漏, 还有就是不需要检查越界, 因为根据定义可知: i >= dp[i], 所以dp[i-dp[i]]的边界情况是dp[0];
4646

47+
## 思路(栈)
48+
主要思路和常规的括号解法一样,遇到'('入栈,遇到')'出栈,并计算两个括号之间的长度。
49+
因为这个题存在非法括号对的情况且求是合法括号对的最大长度 所以有两个注意点是:
50+
1. **栈中存的是符号的下标**
51+
2. **当栈为空时且当前扫描到的符号是')'时,需要将这个符号入栈作为分割符**
52+
4753
## 代码
4854

49-
* 语言支持: Python
55+
* 语言支持: Python, javascript
5056

5157
Python Code:
5258
```
@@ -75,6 +81,29 @@ class Solution:
7581
return mlen
7682
```
7783

84+
javascript code:
85+
```js
86+
// 用栈来解
87+
var longestValidParentheses = function(s) {
88+
let stack = new Array()
89+
let longest = 0
90+
stack.push(-1)
91+
for(let i = 0; i < s.length; i++) {
92+
if (s[i] === '(') {
93+
stack.push(i)
94+
} else {
95+
stack.pop()
96+
if (stack.length === 0) {
97+
stack.push(i)
98+
} else {
99+
longest = Math.max(longest, i - stack[stack.length - 1])
100+
}
101+
}
102+
}
103+
return longest
104+
};
105+
```
106+
78107
## 扩展
79108

80109
1. 如果判断的不仅仅只有'('和')', 还有'[', ']', '{'和'}', 该怎么办?

problems/4.median-of-two-sorted-array.md

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ The median is (2 + 3)/2 = 2.5
3535
#### 解法一 - 暴力 (Brute Force)
3636
暴力解主要是要merge两个排序的数组`(A,B)`成一个排序的数组。
3737

38-
用两个`pointer(i,j)``i` 从数组`A`起始位置开始,即`i=0`开始,`j` 从数组`B`起始位置, 即`j=0`开始.
39-
一一比较 `A[i] 和 B[j]`,
38+
用两个`pointer(i,j)``i` 从数组`A`起始位置开始,即`i=0`开始,`j` 从数组`B`起始位置, 即`j=0`开始.
39+
一一比较 `A[i] 和 B[j]`,
4040
1. 如果`A[i] <= B[j]`, 则把`A[i]` 放入新的数组中,i往后移一位,即 `i+1`.
4141
2. 如果`A[i] > B[j]`, 则把`B[j]` 放入新的数组中,j往后移一位,即 `j+1`.
4242
3. 重复步骤#1#2,直到`i`移到`A`最后,或者`j`移到`B`最后。
43-
4. 如果`j`移动到`B`数组最后,那么直接把剩下的所有`A`依次放入新的数组中.
43+
4. 如果`j`移动到`B`数组最后,那么直接把剩下的所有`A`依次放入新的数组中.
4444
5. 如果`i`移动到`A`数组最后,那么直接把剩下的所有`B`依次放入新的数组中.
4545

4646
Merge的过程如下图。
@@ -76,7 +76,7 @@ Merge的过程如下图。
7676
1. 暴力求解,在线性时间内merge两个排好序的数组成一个数组。
7777
2. 二分查找,关键点在于
7878
- 要partition两个排好序的数组成左右两等份,partition需要满足`len(Aleft)+len(Bleft)=(m+n+1)/2 - m是数组A的长度, n是数组B的长度`
79-
79+
8080
- 并且partition后 A左边最大(`maxLeftA`), A右边最小(`minRightA`), B左边最大(`maxLeftB`), B右边最小(`minRightB`) 满足
8181
`(maxLeftA <= minRightB && maxLeftB <= minRightA)`
8282

@@ -127,7 +127,7 @@ class MedianTwoSortedArrayBruteForce {
127127
}
128128
}
129129
```
130-
*解法二 - 二分查找(Binary Search*
130+
*解法二 - 二分查找(Binary Search)*
131131
```java
132132
class MedianSortedTwoArrayBinarySearch {
133133
public static double findMedianSortedArraysBinarySearch(int[] nums1, int[] nums2) {
@@ -144,13 +144,13 @@ class MedianSortedTwoArrayBinarySearch {
144144
int i = lo + (hi - lo) / 2;
145145
// partition B position j
146146
int j = (m + n + 1) / 2 - i;
147-
147+
148148
int maxLeftA = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
149149
int minRightA = i == m ? Integer.MAX_VALUE : nums1[i];
150-
150+
151151
int maxLeftB = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
152152
int minRightB = j == n ? Integer.MAX_VALUE : nums2[j];
153-
153+
154154
if (maxLeftA <= minRightB && maxLeftB <= minRightA) {
155155
// total length is even
156156
if ((m + n) % 2 == 0) {
@@ -171,3 +171,76 @@ class MedianSortedTwoArrayBinarySearch {
171171
}
172172
}
173173
```
174+
175+
## 代码 (javascript code)
176+
*解法一 - 暴力解法(Brute force)*
177+
```js
178+
/**
179+
* @param {number[]} nums1
180+
* @param {number[]} nums2
181+
* @return {number}
182+
*/
183+
var findMedianSortedArrays = function(nums1, nums2) {
184+
// 归并排序
185+
const merged = []
186+
let i = 0
187+
let j = 0
188+
while(i < nums1.length && j < nums2.length) {
189+
if (nums1[i] < nums2[j]) {
190+
merged.push(nums1[i++])
191+
} else {
192+
merged.push(nums2[j++])
193+
}
194+
}
195+
while(i < nums1.length) {
196+
merged.push(nums1[i++])
197+
}
198+
while(j < nums2.length) {
199+
merged.push(nums2[j++])
200+
}
201+
202+
const { length } = merged
203+
return length % 2 === 1
204+
? merged[Math.floor(length / 2)]
205+
: (merged[length / 2] + merged[length / 2 - 1]) / 2
206+
};
207+
```
208+
209+
*解法二 - 二分查找(Binary Search)*
210+
```js
211+
/**
212+
* 二分解法
213+
* @param {number[]} nums1
214+
* @param {number[]} nums2
215+
* @return {number}
216+
*/
217+
var findMedianSortedArrays = function(nums1, nums2) {
218+
// make sure to do binary search for shorten array
219+
if (nums1.length > nums2.length) {
220+
[nums1, nums2] = [nums2, nums1]
221+
}
222+
const m = nums1.length
223+
const n = nums2.length
224+
let low = 0
225+
let high = m
226+
while(low <= high) {
227+
const i = low + Math.floor((high - low) / 2)
228+
const j = Math.floor((m + n + 1) / 2) - i
229+
230+
const maxLeftA = i === 0 ? -Infinity : nums1[i-1]
231+
const minRightA = i === m ? Infinity : nums1[i]
232+
const maxLeftB = j === 0 ? -Infinity : nums2[j-1]
233+
const minRightB = j === n ? Infinity : nums2[j]
234+
235+
if (maxLeftA <= minRightB && minRightA >= maxLeftB) {
236+
return (m + n) % 2 === 1
237+
? Math.max(maxLeftA, maxLeftB)
238+
: (Math.max(maxLeftA, maxLeftB) + Math.min(minRightA, minRightB)) / 2
239+
} else if (maxLeftA > minRightB) {
240+
high = i - 1
241+
} else {
242+
low = low + 1
243+
}
244+
}
245+
};
246+
```

problems/42.trapping-rain-water.md

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -96,26 +96,16 @@ var trap = function(height) {
9696
Python Code:
9797

9898
```python
99-
10099
class Solution:
101-
def trap(self, height: List[int]) -> int:
102-
maxLeft, maxRight, volum = 0, 0, 0
103-
maxLeftStack, maxRightStack = [], []
104-
for h in height:
105-
if h > maxLeft:
106-
maxLeftStack.append(h)
107-
maxLeft = h
108-
else:
109-
maxLeftStack.append(maxLeft)
110-
for h in height[::-1]:
111-
if h > maxRight:
112-
maxRightStack.append(h)
113-
maxRight = h
114-
else:
115-
maxRightStack.append(maxRight)
116-
maxRightStack = maxRightStack[::-1]
117-
for i in range(1, len(height) - 1):
118-
minSide = min(maxLeftStack[i], maxRightStack[i])
119-
volum += minSide - height[i]
120-
return volum
100+
def trap(self, heights: List[int]) -> int:
101+
n = len(heights)
102+
l, r = [0] * (n + 1), [0] * (n + 1)
103+
ans = 0
104+
for i in range(1, len(heights) + 1):
105+
l[i] = max(l[i - 1], heights[i - 1])
106+
for i in range(len(heights) - 1, 0, -1):
107+
r[i] = max(r[i + 1], heights[i])
108+
for i in range(len(heights)):
109+
ans += max(0, min(l[i + 1], r[i]) - heights[i])
110+
return ans
121111
```

thinkings/basic-data-structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ foo();
171171

172172
![basic-data-structure-call-stack](../assets/thinkings/basic-data-structure-call-stack.png)
173173

174-
> 我画的图没有画出执行上下文中其他部分(this 和 scope 等), 这部分是闭包的关键,而我这里不是将闭包的,是为了讲解栈的。
174+
> 我画的图没有画出执行上下文中其他部分(this 和 scope 等), 这部分是闭包的关键,而我这里不是讲闭包的,是为了讲解栈的。
175175
176176
> 社区中有很多“执行上下文中的 scope 指的是执行栈中父级声明的变量”说法,这是完全错误的, JS 是词法作用域,scope 指的是函数定义时候的父级,和执行没关系
177177

thinkings/run-length-encode-and-huffman-encode.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,11 @@ AAAAABBBBCCC
8181

8282
## 总结
8383

84-
实际情况,我们先用游程编码一遍,然后再用 Huffman 再次编码一次。
84+
游程编码和Huffman都是无损压缩算法,即解压缩过程不会损失原数据任何内容。 实际情况,我们先用游程编码一遍,然后再用 Huffman 再次编码一次。几乎所有的无损压缩格式都用到了它们,比如PNG,GIF,PDF,ZIP等。
85+
86+
对于有损压缩,通常是去除了人类无法识别的颜色,听力频率范围等。也就是说损失了原来的数据。 但由于人类无法识别这部分信息,因此很多情况下都是值得的。这种删除了人类无法感知内容的编码,我们称之为“感知编码”(也许是一个自创的新名词),比如JPEG,MP3等。关于有损压缩不是本文的讨论范围,感兴趣的可以搜素相关资料。
87+
88+
实际上,视频压缩的原理也是类似,只不过视频压缩会用到一些额外的算法,比如“时间冗余”,即仅存储变化的部分,对于不变的部分,存储一次就够了。
8589

8690
## 相关题目
8791

0 commit comments

Comments
 (0)