Skip to content

Commit 1ec5d6d

Browse files
author
lucifer
committed
feat: cpp code
1 parent 104be62 commit 1ec5d6d

File tree

8 files changed

+179
-6
lines changed

8 files changed

+179
-6
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
157157
- [最大公约数](./thinkings/GCD.md)
158158
- [并查集](./thinkings/union-find.md)
159159
- [平衡二叉树专题](./thinkings/balanced-tree.md)
160+
- [蓄水池抽样](./thinkings/reservoid-sampling.md) 🆕
160161
- [单调栈](./thinkings/monotone-stack.md) 🆕
161162

162163
### 精选题解(9 篇)

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
* [最大公约数](thinkings/GCD.md)
2525
* [并查集](thinkings/union-find.md)
2626
* [平衡二叉树专题](thinkings/balanced-tree.md)
27+
* [蓄水池抽样](thinkings/reservoid-sampling.md) 🆕
2728
* [单调栈](thinkings/monotone-stack.md)
2829

2930

problems/1.two-sum.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ https://leetcode-cn.com/problems/two-sum
5353

5454
## 代码
5555

56-
- 语言支持:JS, Go
56+
- 语言支持:JS, Go,CPP
5757

5858
```js
5959
/**
@@ -90,14 +90,30 @@ func twoSum(nums []int, target int) []int {
9090
}
9191
```
9292

93+
CPP Code:
94+
95+
```cpp
96+
class Solution {
97+
public:
98+
vector<int> twoSum(vector<int>& A, int target) {
99+
unordered_map<int, int> m;
100+
for (int i = 0; i < A.size(); ++i) {
101+
int t = target - A[i];
102+
if (m.count(t)) return { m[t], i };
103+
m[A[i]] = i;
104+
}
105+
return {};
106+
}
107+
};
108+
```
109+
93110
**复杂度分析**
94111
95112
- 时间复杂度:$$O(N)$$
96113
- 空间复杂度:$$O(N)$$
97114
98-
更多题解可以访问我的LeetCode题解仓库https://github.com/azl397985856/leetcode 。 目前已经37K star啦
115+
更多题解可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦
99116
100117
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
101118
102-
103119
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg)

problems/15.3sum.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ https://leetcode-cn.com/problems/3sum/
5353

5454
## 代码
5555

56+
代码支持 : JS,CPP
57+
58+
JS Code:
59+
5660
```js
5761
/**
5862
* @param {number[]} nums
@@ -98,7 +102,38 @@ var threeSum = function (nums) {
98102
};
99103
```
100104

105+
CPP Code:
106+
107+
```cpp
108+
class Solution {
109+
public:
110+
vector<vector<int>> threeSum(vector<int>& A) {
111+
sort(begin(A), end(A));
112+
vector<vector<int>> ans;
113+
int N = A.size();
114+
for (int i = 0; i < N - 2; ++i) {
115+
if (i && A[i] == A[i - 1]) continue;
116+
int L = i + 1, R = N - 1;
117+
while (L < R) {
118+
int sum = A[i] + A[L] + A[R];
119+
if (sum == 0) ans.push_back({ A[i], A[L], A[R] });
120+
if (sum >= 0) {
121+
--R;
122+
while (L < R && A[R] == A[R + 1]) --R;
123+
}
124+
if (sum <= 0) {
125+
++L;
126+
while (L < R && A[L] == A[L - 1]) ++L;
127+
}
128+
}
129+
}
130+
return ans;
131+
}
132+
}
133+
```
134+
101135
**复杂度分析**
136+
102137
- 时间复杂度:$$O(N^2)$$
103138
- 空间复杂度:取决于排序算法的空间消耗
104139

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ var findMedianSortedArrays = function (nums1, nums2) {
196196

197197
_解法二 - 二分查找(Binary Search)_
198198

199+
JS Code:
200+
199201
```js
200202
/**
201203
* 二分解法
@@ -234,6 +236,8 @@ var findMedianSortedArrays = function (nums1, nums2) {
234236
};
235237
```
236238

239+
Java Code:
240+
237241
```java
238242
class MedianSortedTwoArrayBinarySearch {
239243
public static double findMedianSortedArraysBinarySearch(int[] nums1, int[] nums2) {
@@ -278,6 +282,30 @@ class MedianSortedTwoArrayBinarySearch {
278282
}
279283
```
280284

285+
CPP Code:
286+
287+
```cpp
288+
class Solution {
289+
public:
290+
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
291+
if (nums1.size() > nums2.size()) swap(nums1, nums2);
292+
int M = nums1.size(), N = nums2.size(), L = 0, R = M, K = (M + N + 1) / 2;
293+
while (true) {
294+
int i = (L + R) / 2, j = K - i;
295+
if (i < M && nums2[j - 1] > nums1[i]) L = i + 1;
296+
else if (i > L && nums1[i - 1] > nums2[j]) R = i - 1;
297+
else {
298+
int maxLeft = max(i ? nums1[i - 1] : INT_MIN, j ? nums2[j - 1] : INT_MIN);
299+
if ((M + N) % 2) return maxLeft;
300+
int minRight = min(i == M ? INT_MAX : nums1[i], j == N ? INT_MAX : nums2[j]);
301+
return (maxLeft + minRight) / 2.0;
302+
}
303+
}
304+
}
305+
};
306+
307+
```
308+
281309
**复杂度分析**
282310
283311
- 时间复杂度:$$O(log(min(m, n)))$$

problems/5.longest-palindromic-substring.md

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ if (s[i] === s[j] && dp[i + 1][j - 1]) {
5151
}
5252
```
5353

54-
5554
## 关键点
5655

5756
- ”延伸“(extend)
5857

5958
## 代码
6059

61-
代码支持:Python,JavaScript
60+
代码支持:Python,JavaScript,CPP
6261

6362
Python Code:
6463

@@ -127,7 +126,37 @@ var longestPalindrome = function (s) {
127126
};
128127
```
129128

130-
**_复杂度分析_**
129+
CPP Code:
130+
131+
```cpp
132+
class Solution {
133+
private:
134+
int expand(string &s, int L, int R) {
135+
while (L >= 0 && R < s.size() && s[L] == s[R]) {
136+
--L;
137+
++R;
138+
}
139+
return R - L - 1;
140+
}
141+
public:
142+
string longestPalindrome(string s) {
143+
if (s.empty()) return s;
144+
int start = 0, maxLen = 0;
145+
for (int i = 0; i < s.size(); ++i) {
146+
int len1 = expand(s, i, i);
147+
int len2 = expand(s, i, i + 1);
148+
int len = max(len1, len2);
149+
if (len > maxLen) {
150+
start = i - (len - 1) / 2;
151+
maxLen = len;
152+
}
153+
}
154+
return s.substr(start, maxLen);
155+
}
156+
};
157+
```
158+
159+
**复杂度分析**
131160
132161
- 时间复杂度:$$O(N^2)$$
133162
- 空间复杂度:$$O(N^2)$$

thinkings/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@
2727
- [最大公约数](GCD.md)
2828
- [并查集](union-find.md)
2929
- [前缀和](prefix.md)
30+
- [蓄水池抽样](reservoid-sampling.md)
3031
- [平衡二叉树专题](balanced-tree.md)

thinkings/reservoid-sampling.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# 蓄水池抽样
2+
3+
力扣中关于蓄水池抽样问题官方标签是 2 道,根据我的做题情况来看,可能有三四道。比重算是比较低的,大家可以根据自己的实际情况选择性掌握。
4+
5+
蓄水池抽样的算法思维很巧妙,代码简单且容易理解,就算不掌握它,作为了解也是很不错的。
6+
7+
## 问题描述
8+
9+
给出一个数据流,我们需要在此数据流中随机选取 k 个数。由于这个数据流的长度很大,因此需要边遍历边处理,而不能将其一次性全部加载到内存。
10+
11+
请写出一个随机选择算法,使得数据流中所有数据被**等概率**选中。
12+
13+
这种问题的表达形式有很多。比如让你随机从一个矩形中抽取 k 个点,随机从一个单词列表中抽取 k 个单词等等,要求你等**概率随机抽取**。不管描述怎么变,其本质上都是一样的。今天我们就来看看如何做这种题。
14+
15+
## 算法描述
16+
17+
这个算法叫蓄水池抽样算法(reservoid sampling)。
18+
19+
其基本思路是:
20+
21+
- 构建一个大小为 k 的数组,将数据流的前 k 个元素放入数组中。
22+
- 对数据流的前 k 个数****不进行任何处理。
23+
- 从数据流的第 k + 1 个数开始,在 [1, i] 之间选一个数 rand,其中 i 表示当前是第几个数。
24+
- 如果 rand 大于等于 k 什么都不做
25+
- 如果 rand 小于 k, 将 rand 和 i 交换,也就是说选择当前的数代替已经被选中的数(备胎)。
26+
- 最终返回幸存的备胎即可
27+
28+
这种算法的核心在于先以某一种概率选取数,并在后续过程以另一种概率换掉之前已经被选中的数。因此实际上每个数被最终选中的概率都是**被选中的概率 \* 不被替换的概率**
29+
30+
伪代码:
31+
32+
> 伪代码参考的某一本算法书,并略有修改。
33+
34+
```py
35+
Init : a reservoir with the size: k
36+
for i= k+1 to N
37+
if(random(1, i) < k) {
38+
SWAP the Mth value and ith value
39+
}
40+
```
41+
42+
这样可以保证被选择的数是等概率的吗?答案是肯定的。
43+
44+
- 当 i <= k ,i 被选中的概率是 1
45+
- 到第 k + 1 个数时,第 k + 1 个数被选中的概率(走进上面的 if 分支的概率)是 $\frac{k}{k+1}$,到第 k + 2 个数时,第 k + 2 个数被选中的概率(走进上面的 if 分支的概率)是 $\frac{k}{k+2}$,以此类推。那么第 n 个数被选中的概率就是 $\frac{k}{n}$
46+
- 上面分析了被选中的概率,接下来分析不被替换的概率。到第 k + 1 个数时,前 k 个数被替换的概率是 $\frac{1}{k}$。到前 k + 2 个数时,第 k + 2 个数被替换的概率是 $\frac{1}{k}$,以此类推。也就是说所有的被替换的概率都是 $\frac{1}{k}$。知道了被替换的概率,那么不被替换的概率其实就是 1 - 被替换的概率。
47+
48+
因此对于前 k 个数,最终被选择的概率都是 1 \* 不被 k + 1 替换的概率 \* 不被 k + 2 替换的概率 \* ... 不被 n 替换的概率,即 1 \* (1 - 被 k + 1 替换的概率) \* (1 - 被 k + 2 替换的概率) \* ... (1 - 被 n 替换的概率),即 $1 \times (1 - \frac{k}{k+1} \times \frac{1}{k}) \times (1 - \frac{k}{k+2} \times \frac{1}{k}) \times ... \times (1 - \frac{k}{n} \times \frac{1}{k}) = \frac{k}{n} $。
49+
50+
对于 第 i (i > k) 个数,最终被选择的概率是 第 i 步被选中的概率 \* 不被第 i + 1 步替换的概率 \* ... \* 不被第 n 步被替换的概率, 即 $\frac{k}{k+1} \times (1 - \frac{k}{k+2} \times \frac{1}{k}) \times ... \times (1 - \frac{k}{n} \times \frac{1}{k}) = \frac{k}{n} $。
51+
52+
总之,不管是哪个数,被选中的概率都是 $\frac{k}{n}$,满足概率相等的需求。
53+
54+
## 相关题目
55+
56+
- [382. 链表随机节点](https://leetcode-cn.com/problems/linked-list-random-node/ "382. 链表随机节点")
57+
- [398. 随机数索引](https://leetcode-cn.com/problems/random-pick-index/ "398. 随机数索引")
58+
- [497. 非重叠矩形中的随机点](https://leetcode-cn.com/problems/random-point-in-non-overlapping-rectangles/ "497. 非重叠矩形中的随机点")
59+
60+
## 总结
61+
62+
蓄水池抽样算法核心代码非常简单。但是却不容易想到,尤其是之前没见过的情况下。其核心点在于每个数被最终选中的概率都是**被选中的概率 \* 不被替换的概率**。于是我们可以采取某一种动态手段,使得每一轮都有概率选中和替换一些数字。 上面我们有给出了概率相等的证明过程,大家不妨自己尝试证明一下。之后结合文末的相关题目练习一下,效果会更好。

0 commit comments

Comments
 (0)