Skip to content

Commit c763807

Browse files
author
lucifer
committed
2 parents e4394dd + 6ca34be commit c763807

5 files changed

+175
-15
lines changed

README.en.md

100644100755
+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ The data structures mainly include:
235235
- [0023.merge-k-sorted-lists](./problems/23.merge-k-sorted-lists.md)
236236
- [0025.reverse-nodes-in-k-group](./problems/25.reverse-nodes-in-k-groups-en.md) 🆕✅
237237
- [0032.longest-valid-parentheses](./problems/32.longest-valid-parentheses.md) 🆕
238-
- [0042.trapping-rain-water](./problems/42.trapping-rain-water.md)
238+
- [0042.trapping-rain-water](./problems/42.trapping-rain-water.en.md)🆕✅
239239
- [0052.N-Queens-II](./problems/52.N-Queens-II.md) 🆕
240240
- [0124.binary-tree-maximum-path-sum](./problems/124.binary-tree-maximum-path-sum.md)
241241
- [0128.longest-consecutive-sequence](./problems/128.longest-consecutive-sequence.md)

problems/124.binary-tree-maximum-path-sum.md

+22-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Output: 42
7878

7979
## 代码
8080

81-
代码支持:JavaScript,Java
81+
代码支持:JavaScript,Java,Python
8282

8383
- JavaScript
8484

@@ -154,5 +154,26 @@ class Solution {
154154
}
155155
```
156156

157+
- Python
158+
159+
```py
160+
161+
class Solution:
162+
ans = float('-inf')
163+
def maxPathSum(self, root: TreeNode) -> int:
164+
def helper(node):
165+
if not node: return 0
166+
l = helper(node.left)
167+
r = helper(node.right)
168+
self.ans = max(self.ans, max(l,0) + max(r, 0) + node.val)
169+
return max(l, r, 0) + node.val
170+
helper(root)
171+
return self.ans
172+
```
173+
157174
## 相关题目
158175
- [113.path-sum-ii](./113.path-sum-ii.md)
176+
177+
## 扩展
178+
179+
实际上这道题,当遍历到某一个节点的时候,我们需要子节点的信息,然后同时结合自身的 val 来决定要不要选取左右子树。 因此这个过程本质上就是`后序遍历`

problems/42.trapping-rain-water.en.md

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
## Trapping Rain Water
2+
https://leetcode.com/problems/trapping-rain-water/description/
3+
4+
## Problem Description
5+
> Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
6+
7+
![42.trapping-rain-water-1](../assets/problems/42.trapping-rain-water-1.png)
8+
9+
> The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
10+
11+
```
12+
Input: [0,1,0,2,1,0,1,3,2,1,2,1]
13+
Output: 6
14+
```
15+
16+
## Solution
17+
18+
The difficulty of this problem is `hard`.
19+
We'd like to compute how much water a given elevation map can trap.
20+
21+
A brute force solution would be adding up the maximum level of water that each element of the map can trap.
22+
23+
Pseudo Code:
24+
```js
25+
for(let i = 0; i < height.length; i++) {
26+
area += h[i] - height[i]; // the maximum level of water that the element i can trap
27+
}
28+
```
29+
30+
Now the problem becomes how to calculating h[i], which is in fact the minimum of maximum height of bars on both sides minus height[i]:
31+
`h[i] = Math.min(leftMax, rightMax)` where `leftMax = Math.max(leftMax[i-1], height[i])` and `rightMax = Math.max(rightMax[i+1], height[i])`.
32+
33+
For the given example, h would be [0, 1, 1, 2, 2, 2 ,2, 3, 2, 2, 2, 1].
34+
35+
The key is to calculate `leftMax` and `rightMax`.
36+
37+
## Key Points
38+
39+
- Figure out the modeling of `h[i] = Math.min(leftMax, rightMax)`
40+
41+
## Code (JavaScript/Python3/C++)
42+
43+
JavaScript Code:
44+
45+
```js
46+
47+
/*
48+
* @lc app=leetcode id=42 lang=javascript
49+
*
50+
* [42] Trapping Rain Water
51+
*
52+
*/
53+
/**
54+
* @param {number[]} height
55+
* @return {number}
56+
*/
57+
var trap = function(height) {
58+
let max = 0;
59+
let volumn = 0;
60+
const leftMax = [];
61+
const rightMax = [];
62+
63+
for(let i = 0; i < height.length; i++) {
64+
leftMax[i] = max = Math.max(height[i], max);
65+
}
66+
67+
max = 0;
68+
69+
for(let i = height.length - 1; i >= 0; i--) {
70+
rightMax[i] = max = Math.max(height[i], max);
71+
}
72+
73+
for(let i = 0; i < height.length; i++) {
74+
volumn = volumn + Math.min(leftMax[i], rightMax[i]) - height[i]
75+
}
76+
77+
return volumn;
78+
};
79+
80+
```
81+
82+
Python Code:
83+
84+
```python
85+
class Solution:
86+
def trap(self, heights: List[int]) -> int:
87+
n = len(heights)
88+
l, r = [0] * (n + 1), [0] * (n + 1)
89+
ans = 0
90+
for i in range(1, len(heights) + 1):
91+
l[i] = max(l[i - 1], heights[i - 1])
92+
for i in range(len(heights) - 1, 0, -1):
93+
r[i] = max(r[i + 1], heights[i])
94+
for i in range(len(heights)):
95+
ans += max(0, min(l[i + 1], r[i]) - heights[i])
96+
return ans
97+
```
98+
99+
C++ code:
100+
101+
```c++
102+
class Solution {
103+
public:
104+
int trap(vector<int>& height) {
105+
//check for empty input array
106+
if(height.empty())
107+
return 0;
108+
int size = height.size();
109+
int leftMax[size], rightMax[size];
110+
//initialization
111+
leftMax[0] = height[0];
112+
rightMax[size - 1] = height[size - 1];
113+
//find leftMax for each element i
114+
for(int i = 1; i < size; ++i)
115+
leftMax[i] = max(leftMax[i-1], height[i]);
116+
//find rightMax for each element i
117+
for(int i = size - 2; i >= 0; --i)
118+
rightMax[i] = max(rightMax[i+1], height[i]);
119+
//caculating the result
120+
int ans = 0;
121+
for(int i = 0; i < size; ++i)
122+
ans += min(leftMax[i], rightMax[i]) - height[i];
123+
return ans;
124+
}
125+
};
126+
```
127+
128+
## Similar Problems
129+
130+
- [84.largest-rectangle-in-histogram](https://github.com/azl397985856/leetcode/blob/master/problems/84.largest-rectangle-in-histogram.md)

thinkings/binary-tree-traversal.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ BFS 的关键点在于如何记录每一层次是否遍历完成, 我们可以
103103

104104
## 双色标记法
105105

106-
我们直到垃圾回收算法中,有一种算法叫三色标记法。 即:
106+
我们知道垃圾回收算法中,有一种算法叫三色标记法。 即:
107107

108108
- 用白色表示尚未访问
109109
- 灰色表示尚未完全访问子节点
@@ -137,7 +137,7 @@ class Solution:
137137
return res
138138
```
139139

140-
如要实现前序、后序遍历,只需要调整左右子节点的入栈顺序即可。
140+
如要实现前序、后序遍历,只需要调整左右子节点的入栈顺序即可。可以看出使用三色标记法, 其写法类似递归的形式,因此便于记忆和书写,缺点是使用了额外的内存空间。不过这个额外的空间是线性的,影响倒是不大。
141141

142142
## Morris 遍历
143143

thinkings/bloom-filter.md

+20-11
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,53 @@
11
## 场景
2+
23
假设你现在要处理这样一个问题,你有一个网站并且拥有`很多`访客,每当有用户访问时,你想知道这个ip是不是第一次访问你的网站。
34

45
### hashtable 可以么
5-
一个显而易见的答案是将所有的ip用hashtable存起来,每次访问都去hashtable中取,然后判断即可。但是题目说了网站有`很多`访客,
6-
假如有10亿个用户访问过,每个ip的长度是4 byte,那么你一共需要4 * 1000000000 = 4000000000Bytes = 4G , 如果是判断URL黑名单,
7-
由于每个URL会更长,那么需要的空间可能会远远大于你的期望。
6+
7+
一个显而易见的答案是将所有的 IP 用 hashtable 存起来,每次访问都去 hashtable 中取,然后判断即可。但是题目说了网站有`很多`访客,
8+
假如有10亿个用户访问过,假设 IP 是 IPV4, 那么每个 IP 的长度是 4 byte,那么你一共需要4 * 1000000000 = 4000000000Bytes = 4G 。
9+
10+
如果是判断 URL 黑名单,由于每个 URL 会更长(可能远大于上面 IPV4 地址的 4 byte),那么需要的空间可能会远远大于你的期望。
811

912
### bit
10-
另一个稍微难想到的解法是bit, 我们知道bit有0和1两种状态,那么用来表示存在,不存在再合适不过了。
1113

12-
加入有10亿个ip,我们就可以用10亿个bit来存储,那么你一共需要 1 * 1000000000 = (4000000000 / 8) Bytes = 128M, 变为原来的1/32,
13-
如果是存储URL这种更长的字符串,效率会更高。
14+
另一个稍微难想到的解法是bit, 我们知道bit有 0 和 1 两种状态,那么用来表示**存在****不存在**再合适不过了。
15+
16+
假如有 10 亿个 IP,就可以用 10 亿个 bit 来存储,那么你一共需要 1 * 1000000000 = (4000000000 / 8) Bytes = 128M, 变为原来的1/32, 如果是存储URL这种更长的字符串,效率会更高。 问题是,我们怎么把 IPV4 和 bit 的位置关联上呢?
1417

15-
基于这种想法,我们只需要两个操作,set(ip) 和 has(ip)
18+
比如`192.168.1.1` 应该是用第几位表示,`10.18.1.1` 应该是用第几位表示呢? 答案是使用哈希函数。
19+
20+
基于这种想法,我们只需要两个操作,set(ip) 和 has(ip),以及一个内置函数 hash(ip) 用于将 IP 映射到 bit 表。
1621

1722
这样做有两个非常致命的缺点:
1823

1924
1. 当样本分布极度不均匀的时候,会造成很大空间上的浪费
2025

21-
> 我们可以通过散列函数来解决
26+
> 我们可以通过优化散列函数来解决
2227
2328
2. 当元素不是整型(比如URL)的时候,BitSet就不适用了
2429

2530
> 我们还是可以使用散列函数来解决, 甚至可以多hash几次
2631
2732
### 布隆过滤器
2833

29-
布隆过滤器其实就是`bit + 多个散列函数`, 如果经过多次散列的值再bit上都为1,那么可能存在(可能有冲突)。 如果
30-
有一个不为1,那么一定不存在(一个值经过散列函数得到的值一定是唯一的),这也是布隆过滤器的一个重要特点。
34+
布隆过滤器其实就是`bit + 多个散列函数`。k 次 hash(ip) 会生成多个索引,并将其 k 个索引位置的二进制置为 1。 如果经过 k 个索引位置的值都为 1,那么认为其**可能存在**(因为有冲突的可能)。 如果有一个不为1,那么**一定不存在**(一个值经过散列函数得到的值一定是唯一的),这也是布隆过滤器的一个重要特点。也就是说布隆过滤器回答了:**可能存在****一定不存在** 的问题。
3135

3236
![bloom-filter-url](../assets/thinkings/bloom-filter-url.png)
3337

38+
从上图可以看出, 布隆过滤器本质上是由**一个很长的二进制向量****多个哈希函数**组成。
39+
40+
由于没有 hashtable 的100% 可靠性,因此这本质上是一种**可靠性换取空间的做法**。除了可靠性,布隆过滤器删除起来也比较麻烦。
41+
3442
### 布隆过滤器的应用
3543

3644
1. 网络爬虫
45+
3746
判断某个URL是否已经被爬取过
3847

3948
2. K-V数据库 判断某个key是否存在
4049

41-
比如Hbase的每个Region中都包含一个BloomFilter,用于在查询时快速判断某个key在该region中是否存在
50+
比如 Hbase 的每个 Region 中都包含一个 BloomFilter,用于在查询时快速判断某个 key 在该 region 中是否存在
4251

4352
3. 钓鱼网站识别
4453

0 commit comments

Comments
 (0)