From 4fa39a5a47708e9a7cb13cf664acbbfc4a3d5a7b Mon Sep 17 00:00:00 2001
From: "ningwei.shi"
Date: Tue, 10 Nov 2020 15:32:02 +0800
Subject: [PATCH 01/63] =?UTF-8?q?=E6=8A=A2=E6=88=BF=E5=AD=90Python3?=
=?UTF-8?q?=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
动态规划系列/抢房子.md | 60 +++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/动态规划系列/抢房子.md b/动态规划系列/抢房子.md
index 8dae329..ed50060 100644
--- a/动态规划系列/抢房子.md
+++ b/动态规划系列/抢房子.md
@@ -259,3 +259,63 @@ int[] dp(TreeNode root) {
+[Shantom](https://github.com/Shantom) 提供 198. House Robber I Python3 解法代码:
+
+```Python
+class Solution:
+ def rob(self, nums: List[int]) -> int:
+ # 当前,上一间,上上间
+ cur, pre1, pre2 = 0, 0, 0
+
+ for num in nums:
+ # 当前 = max(上上间+(抢当前),上间(放弃当前))
+ cur = max(pre2 + num, pre1)
+ pre2 = pre1
+ pre1 = cur
+
+ return cur
+```
+[Shantom](https://github.com/Shantom) 提供 213. House Robber II Python3 解法代码:
+
+```Python
+class Solution:
+ def rob(self, nums: List[int]) -> int:
+ # 只有一间时不成环
+ if len(nums) == 1:
+ return nums[0]
+
+ # 该函数同198题
+ def subRob(nums: List[int]) -> int:
+ # 当前,上一间,上上间
+ cur, pre1, pre2 = 0, 0, 0
+ for num in nums:
+ # 当前 = max(上上间+(抢当前),上间(放弃当前))
+ cur = max(pre2 + num, pre1)
+ pre2 = pre1
+ pre1 = cur
+ return cur
+
+ # 不考虑第一间或者不考虑最后一间
+ return max(subRob(nums[:-1]), subRob(nums[1:]))
+```
+[Shantom](https://github.com/Shantom) 提供 337. House Robber III Python3 解法代码:
+
+```Python
+class Solution:
+ def rob(self, root: TreeNode) -> int:
+ # 返回值0项为不抢该节点,1项为抢该节点
+ def dp(root):
+ if not root:
+ return 0, 0
+
+ left = dp(root.left)
+ right = dp(root.right)
+
+ do = root.val + left[0] + right[0]
+ do_not = max(left) + max(right)
+
+ return do_not, do
+
+ return max(dp(root))
+```
+
From d0f78c9b7ae615d9af9fc80b8eb05d351a174acb Mon Sep 17 00:00:00 2001
From: Rui Yang <35053274+littlecry@users.noreply.github.com>
Date: Tue, 10 Nov 2020 22:57:11 -0600
Subject: [PATCH 02/63] =?UTF-8?q?Update=20=E5=8D=95=E8=B0=83=E6=A0=88.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
add Java solution for Leetcode 739. Daily Temperatures
---
数据结构系列/单调栈.md | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/单调栈.md b/数据结构系列/单调栈.md
index fca0ca8..7853fc1 100644
--- a/数据结构系列/单调栈.md
+++ b/数据结构系列/单调栈.md
@@ -181,4 +181,19 @@ vector nextGreaterElements(vector& nums) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+// 739. Daily Temperatures
+class Solution {
+ public int[] dailyTemperatures(int[] T) {
+ Stack stack = new Stack<>();
+ int[] ans = new int[T.length];
+ for (int i = 0; i < T.length; i++) {
+ while (!stack.isEmpty() && T[i] > T[stack.peek()]) {
+ int index = stack.pop();
+ ans[index] = i - index;
+ }
+ stack.push(i);
+ }
+ return ans;
+ }
+}
From 91e56f8727f7d5ef1ec5bd1da9944f89592fd196 Mon Sep 17 00:00:00 2001
From: Rui Yang <35053274+littlecry@users.noreply.github.com>
Date: Tue, 10 Nov 2020 23:16:02 -0600
Subject: [PATCH 03/63] =?UTF-8?q?Update=20=E5=8D=95=E8=B0=83=E6=A0=88.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
add comments
---
数据结构系列/单调栈.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/数据结构系列/单调栈.md b/数据结构系列/单调栈.md
index 7853fc1..cd68be1 100644
--- a/数据结构系列/单调栈.md
+++ b/数据结构系列/单调栈.md
@@ -188,8 +188,10 @@ class Solution {
Stack stack = new Stack<>();
int[] ans = new int[T.length];
for (int i = 0; i < T.length; i++) {
+ // 如果压栈之后不满足单调递减,弹出元素,直至保持单调性
while (!stack.isEmpty() && T[i] > T[stack.peek()]) {
int index = stack.pop();
+ // 被弹出的元素(T[index])都是小于当前的元素(T[i]),由于栈内元素单调递减,大于被弹出元素(index)的最近的就是当前元素(i)
ans[index] = i - index;
}
stack.push(i);
From 93eada462d65a454b3be91c3d1633c0905b4e495 Mon Sep 17 00:00:00 2001
From: MoguCloud
Date: Wed, 11 Nov 2020 13:33:41 +0800
Subject: [PATCH 04/63] =?UTF-8?q?=E3=80=9028.=E5=AE=9E=E7=8E=B0=20strStr()?=
=?UTF-8?q?=E3=80=91=E3=80=90Python=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../动态规划之KMP字符匹配算法.md | 38 ++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/动态规划之KMP字符匹配算法.md b/动态规划系列/动态规划之KMP字符匹配算法.md
index a0cc4ce..5cde805 100644
--- a/动态规划系列/动态规划之KMP字符匹配算法.md
+++ b/动态规划系列/动态规划之KMP字符匹配算法.md
@@ -431,4 +431,40 @@ KMP 算法也就是动态规划那点事,我们的公众号文章目录有一
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+[MoguCloud](https://github.com/MoguCloud) 提供 实现 strStr() 的 Python 完整代码:
+```py
+class Solution:
+ def strStr(self, haystack: str, needle: str) -> int:
+ # 边界条件判断
+ if not needle:
+ return 0
+ pat = needle
+ txt = haystack
+
+ M = len(pat)
+ # dp[状态][字符] = 下个状态
+ dp = [[0 for _ in range(256)] for _ in pat]
+ # base case
+ dp[0][ord(pat[0])] = 1
+ # 影子状态 X 初始化为 0
+ X = 0
+ for j in range(1, M):
+ for c in range(256):
+ dp[j][c] = dp[X][c]
+ dp[j][ord(pat[j])] = j + 1
+ # 更新影子状态
+ X = dp[X][ord(pat[j])]
+
+ N = len(txt)
+ # pat 初始状态为 0
+ j = 0
+ for i in range(N):
+ # 计算 pat 的下一个状态
+ j = dp[j][ord(txt[i])]
+ # 到达终止态,返回结果
+ if j == M:
+ return i - M + 1
+ # 没到达终止态,匹配失败
+ return -1
+```
From 9606d3437f148a32236fd55342faedb9b40994d6 Mon Sep 17 00:00:00 2001
From: Victor Wu
Date: Wed, 11 Nov 2020 13:37:05 +0800
Subject: [PATCH 05/63] =?UTF-8?q?=E4=B8=BA=E8=AE=BE=E8=AE=A1Twitter?=
=?UTF-8?q?=E4=B8=80=E6=96=87=EF=BC=8C=E5=AE=9E=E7=8E=B0C++=E7=89=88?=
=?UTF-8?q?=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
严格遵守框架。时间戳改成全局变量,并分模块拆开写(参照Java思路)
---
数据结构系列/设计Twitter.md | 119 +++++++++++++++++++++++++++-
1 file changed, 118 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/设计Twitter.md b/数据结构系列/设计Twitter.md
index 399fbbb..5f6c5f5 100644
--- a/数据结构系列/设计Twitter.md
+++ b/数据结构系列/设计Twitter.md
@@ -302,4 +302,121 @@ PS:本文前两张图片和 GIF 是我第一次尝试用平板的绘图软件
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[happy-yuxuan](https://github.com/happy-yuxuan) 提供 C++ 代码:
+
+```c++
+static int timestamp = 0;
+class Tweet {
+private:
+ int id;
+ int time;
+public:
+ Tweet *next;
+ // id为推文内容,time为发文时间
+ Tweet(int id, int time) {
+ this->id = id;
+ this->time = time;
+ next = nullptr;
+ }
+ int getId() const {
+ return this->id;
+ }
+ int getTime() const {
+ return this->time;
+ }
+};
+class User {
+private:
+ int id;
+public:
+ Tweet *head; // 发布的Twitter,用链表表示
+ unordered_set followed; // 用户关注了那些人
+ User(int userId) {
+ this->id = userId;
+ head = nullptr;
+ // 要先把自己关注了
+ followed.insert(id);
+ }
+ void follow(int userId) {
+ followed.insert(userId);
+ }
+ void unfollow(int userId) {
+ // 不可以取关自己
+ if (userId != this->id)
+ followed.erase(userId);
+ }
+ void post(int contentId) {
+ Tweet *twt = new Tweet(contentId, timestamp);
+ timestamp++;
+ // 将新建的推文插入链表头
+ // 越靠前的推文 timestamp 值越大
+ twt->next = head;
+ head = twt;
+ }
+};
+class Twitter {
+private:
+ // 映射将 userId 和 User 对象对应起来
+ unordered_map userMap;
+ // 判断该用户存不存在系统中,即userMap中存不存在id
+ inline bool contain(int id) {
+ return userMap.find(id) != userMap.end();
+ }
+public:
+ Twitter() {
+ userMap.clear();
+ }
+ /* user 发表一条 tweet 动态 */
+ void postTweet(int userId, int tweetId) {
+ if (!contain(userId))
+ userMap[userId] = new User(userId);
+ userMap[userId]->post(tweetId);
+ }
+ /* 返回该 user 关注的人(包括他自己)最近的动态 id,
+ 最多 10 条,而且这些动态必须按从新到旧的时间线顺序排列。*/
+ vector getNewsFeed(int userId) {
+ vector ret;
+ if (!contain(userId)) return ret;
+ // 构造一个自动通过Tweet发布的time属性从大到小排序的二叉堆
+ typedef function Compare;
+ Compare cmp = [](const Tweet *a, const Tweet *b) {
+ return a->getTime() < b->getTime();
+ };
+ priority_queue, Compare> q(cmp);
+ // 关注列表的用户Id
+ unordered_set &users = userMap[userId]->followed;
+ // 先将所有链表头节点插入优先级队列
+ for (int id : users) {
+ if (!contain(id)) continue;
+ Tweet *twt = userMap[id]->head;
+ if (twt == nullptr) continue;
+ q.push(twt);
+ }
+ while (!q.empty()) {
+ Tweet *t = q.top(); q.pop();
+ ret.push_back(t->getId());
+ if (ret.size() == 10) return ret; // 最多返回 10 条就够了
+ if (t->next)
+ q.push(t->next);
+ }
+ return ret;
+ }
+ /* follower 关注 followee */
+ void follow(int followerId, int followeeId) {
+ // 若 follower 不存在,则新建
+ if (!contain(followerId))
+ userMap[followerId] = new User(followerId);
+ // 若 followee 不存在,则新建
+ if (!contain(followeeId))
+ userMap[followeeId] = new User(followeeId);
+ userMap[followerId]->follow(followeeId);
+ }
+ /* follower 取关 followee,如果 Id 不存在则什么都不做 */
+ void unfollow(int followerId, int followeeId) {
+ if (contain(followerId))
+ userMap[followerId]->unfollow(followeeId);
+ }
+};
+```
\ No newline at end of file
From 0ac247684ae8833de785130a950dd52ca661370e Mon Sep 17 00:00:00 2001
From: tonytang731 <50162066+tonytang731@users.noreply.github.com>
Date: Wed, 11 Nov 2020 00:51:19 -0500
Subject: [PATCH 06/63] =?UTF-8?q?[875.=20koko=E5=81=B7=E9=A6=99=E8=95=89][?=
=?UTF-8?q?Python3]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/koko偷香蕉.md | 41 ++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/koko偷香蕉.md b/高频面试系列/koko偷香蕉.md
index cc880dd..75109d6 100644
--- a/高频面试系列/koko偷香蕉.md
+++ b/高频面试系列/koko偷香蕉.md
@@ -169,4 +169,43 @@ for (int i = 0; i < n; i++)
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+```python
+import math
+
+class Solution:
+ def minEatingSpeed(self, piles, H):
+ # 初始化起点和终点, 最快的速度可以一次拿完最大的一堆
+ start = 1
+ end = max(piles)
+
+ # while loop进行二分查找
+ while start + 1 < end:
+ mid = start + (end - start) // 2
+
+ # 如果中点所需时间大于H, 我们需要加速, 将起点设为中点
+ if self.timeH(piles, mid) > H:
+ start = mid
+ # 如果中点所需时间小于H, 我们需要减速, 将终点设为中点
+ else:
+ end = mid
+
+ # 提交前确认起点是否满足条件,我们要尽量慢拿
+ if self.timeH(piles, start) <= H:
+ return start
+
+ # 若起点不符合, 则中点是答案
+ return end
+
+
+
+ def timeH(self, piles, K):
+ # 初始化时间
+ H = 0
+
+ #求拿每一堆需要多长时间
+ for pile in piles:
+ H += math.ceil(pile / K)
+
+ return H
+```
From 4870bf9504542870f41e2762cab28785158229d1 Mon Sep 17 00:00:00 2001
From: Victor Wu
Date: Wed, 11 Nov 2020 13:52:53 +0800
Subject: [PATCH 07/63] =?UTF-8?q?=E8=A1=A5=E5=85=85Java=E4=BB=A3=E7=A0=81?=
=?UTF-8?q?=E4=B8=AD=E6=BC=8F=E6=8E=89=E4=BA=86=E4=B8=80=E4=B8=AA=E5=A4=A7?=
=?UTF-8?q?=E6=8B=AC=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/消失的元素.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/高频面试系列/消失的元素.md b/高频面试系列/消失的元素.md
index 844b5cb..5d65c2a 100644
--- a/高频面试系列/消失的元素.md
+++ b/高频面试系列/消失的元素.md
@@ -89,6 +89,7 @@ int missingNumber(int[] nums) {
for (int x : nums)
sum += x;
return expect - sum;
+}
```
你看,这种解法应该是最简单的,但说实话,我自己也没想到这个解法,而且我去问了几个大佬,他们也没想到这个最简单的思路。相反,如果去问一个初中生,他也许很快就能想到。
From c1237d7155658f77b7f26426ca36b5ee9b09caa6 Mon Sep 17 00:00:00 2001
From: tonytang731 <50162066+tonytang731@users.noreply.github.com>
Date: Wed, 11 Nov 2020 01:06:53 -0500
Subject: [PATCH 08/63] =?UTF-8?q?Update=20koko=E5=81=B7=E9=A6=99=E8=95=89.?=
=?UTF-8?q?md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/koko偷香蕉.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/高频面试系列/koko偷香蕉.md b/高频面试系列/koko偷香蕉.md
index 75109d6..635291c 100644
--- a/高频面试系列/koko偷香蕉.md
+++ b/高频面试系列/koko偷香蕉.md
@@ -170,6 +170,8 @@ for (int i = 0; i < n; i++)
======其他语言代码======
+
+[tonytang731](https://https://github.com/tonytang731) 提供 Python3 代码:
```python
import math
From cd51fcf2b62b7a242d3d21949254e1a233207d76 Mon Sep 17 00:00:00 2001
From: Victor Wu
Date: Wed, 11 Nov 2020 14:02:23 +0800
Subject: [PATCH 09/63] =?UTF-8?q?=E3=80=90268.=20=E4=B8=A2=E5=A4=B1?=
=?UTF-8?q?=E7=9A=84=E6=95=B0=E5=AD=97=E3=80=91=E3=80=90C++=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/消失的元素.md | 47 ++++++++++++++++++++++++++-
1 file changed, 46 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/消失的元素.md b/高频面试系列/消失的元素.md
index 844b5cb..50556ba 100644
--- a/高频面试系列/消失的元素.md
+++ b/高频面试系列/消失的元素.md
@@ -132,4 +132,49 @@ public int missingNumber(int[] nums) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[happy-yuxuan](https://github.com/happy-yuxuan) 提供 三种方法的 C++ 代码:
+
+```c++
+// 方法:异或元素和索引
+int missingNumber(vector& nums) {
+ int n = nums.size();
+ int res = 0;
+ // 先和新补的索引异或一下
+ res ^= n;
+ // 和其他的元素、索引做异或
+ for (int i = 0; i < n; i++)
+ res ^= i ^ nums[i];
+ return res;
+}
+```
+
+```c++
+// 方法:等差数列求和
+int missingNumber(vector& nums) {
+ int n = nums.size();
+ // 公式:(首项 + 末项) * 项数 / 2
+ int expect = (0 + n) * (n + 1) / 2;
+ int sum = 0;
+ for (int x : nums)
+ sum += x;
+ return expect - sum;
+}
+```
+
+```c++
+// 方法:防止整型溢出
+int missingNumber(vector& nums) {
+ int n = nums.size();
+ int res = 0;
+ // 新补的索引
+ res += n - 0;
+ // 剩下索引和元素的差加起来
+ for (int i = 0; i < n; i++)
+ res += i - nums[i];
+ return res;
+}
+```
+
+
From 88fe014eb64275d4909f7f27fa03fd2246dbdca3 Mon Sep 17 00:00:00 2001
From: Justlxb0124 <33374844+Justlxb0124@users.noreply.github.com>
Date: Wed, 11 Nov 2020 14:23:01 +0800
Subject: [PATCH 10/63] =?UTF-8?q?Update=20=E5=8D=95=E8=B0=83=E9=98=9F?=
=?UTF-8?q?=E5=88=97.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
数据结构系列/单调队列.md | 49 +++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/单调队列.md b/数据结构系列/单调队列.md
index eb298a1..d82dbe0 100644
--- a/数据结构系列/单调队列.md
+++ b/数据结构系列/单调队列.md
@@ -210,4 +210,51 @@ vector maxSlidingWindow(vector& nums, int k) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+```java
+class Solution {
+ public int[] maxSlidingWindow(int[] nums, int k) {
+ int len = nums.length;
+ // 判断数组或者窗口长度为0的情况
+ if (len * k == 0) {
+ return new int[0];
+ }
+
+ /*
+ 采用两端扫描的方法
+ 将数组分成大小为 k 的若干个窗口, 对每个窗口分别从左往右和从右往左扫描, 记录扫描的最大值
+ left[] 记录从左往右扫描的最大值
+ right[] 记录从右往左扫描的最大值
+ */
+ int[] left = new int[len];
+ int[] right = new int[len];
+
+ for (int i = 0; i < len; i = i + k) {
+ // 每个窗口中的第一个值
+ left[i] = nums[i];
+ // 窗口的最后边界
+ int index = i + k - 1 >= len ? len - 1 : i + k - 1;
+ // 每个窗口的最后一个值
+ right[index] = nums[index];
+ // 对该窗口从左往右扫描
+ for (int j = i + 1; j <= index; j++) {
+ left[j] = Math.max(left[j - 1], nums[j]);
+ }
+ // 对该窗口从右往左扫描
+ for (int j = index - 1; j >= i; j--) {
+ right[j] = Math.max(right[j + 1], nums[j]);
+ }
+ }
+
+ int[] arr = new int[len - k + 1];
+
+ // 对于第 i 个位置, 它一定是该窗口从右往左扫描数组中的最后一个值, 相对的 i + k - 1 是该窗口从左向右扫描数组中的最后一个位置
+ // 对两者取最大值即可
+ for (int i = 0; i < len - k + 1; i++) {
+ arr[i] = Math.max(right[i], left[i + k - 1]);
+ }
+
+ return arr;
+ }
+}
+```
From a72173b1ef5c3660b47b8364ca3e19ee5a7b7478 Mon Sep 17 00:00:00 2001
From: dekunma <53892579+dekunma@users.noreply.github.com>
Date: Wed, 11 Nov 2020 14:23:51 +0800
Subject: [PATCH 11/63] =?UTF-8?q?=E3=80=90392.=20=E5=88=A4=E6=96=AD?=
=?UTF-8?q?=E5=AD=90=E5=BA=8F=E5=88=97=E3=80=91=E3=80=90C++=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../二分查找判定子序列.md | 65 ++++++++++++++++++-
1 file changed, 64 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/二分查找判定子序列.md b/高频面试系列/二分查找判定子序列.md
index c71e65f..e9c5b0f 100644
--- a/高频面试系列/二分查找判定子序列.md
+++ b/高频面试系列/二分查找判定子序列.md
@@ -168,4 +168,67 @@ boolean isSubsequence(String s, String t) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+[dekunma](https://www.linkedin.com/in/dekun-ma-036a9b198/) 提供C++代码
+**解法一:遍历(也可以用双指针):**
+```C++
+class Solution {
+public:
+ bool isSubsequence(string s, string t) {
+ // 遍历s
+ for(int i = 0; i < s.size(); i++) {
+ // 找到s[i]字符在t中的位置
+ size_t pos = t.find(s[i]);
+
+ // 如果s[i]字符不在t中,返回false
+ if(pos == std::string::npos) return false;
+ // 如果s[i]在t中,后面就只看pos以后的字串,防止重复查找
+ else t = t.substr(pos + 1);
+ }
+ return true;
+ }
+};
+```
+
+**解法二:二分查找:**
+```C++
+class Solution {
+public:
+ bool isSubsequence(string s, string t) {
+ int m = s.size(), n = t.size();
+ // 对 t 进行预处理
+ vector index[256];
+ for (int i = 0; i < n; i++) {
+ char c = t[i];
+ index[c].push_back(i);
+ }
+ // 串 t 上的指针
+ int j = 0;
+ // 借助 index 查找 s[i]
+ for (int i = 0; i < m; i++) {
+ char c = s[i];
+ // 整个 t 压根儿没有字符 c
+ if (index[c].empty()) return false;
+ int pos = left_bound(index[c], j);
+ // 二分搜索区间中没有找到字符 c
+ if (pos == index[c].size()) return false;
+ // 向前移动指针 j
+ j = index[c][pos] + 1;
+ }
+ return true;
+ }
+ // 查找左侧边界的二分查找
+ int left_bound(vector arr, int tar) {
+ int lo = 0, hi = arr.size();
+ while (lo < hi) {
+ int mid = lo + (hi - lo) / 2;
+ if (tar > arr[mid]) {
+ lo = mid + 1;
+ } else {
+ hi = mid;
+ }
+ }
+ return lo;
+ }
+};
+```
From 1c871a9eb0d5a556b41409ac86750b878dd72e17 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9C=B1=E5=8A=9B?= <171250568@smail.nju.edu.cn>
Date: Wed, 11 Nov 2020 14:41:25 +0800
Subject: [PATCH 12/63] =?UTF-8?q?=E3=80=90645.=20=E9=94=99=E8=AF=AF?=
=?UTF-8?q?=E7=9A=84=E9=9B=86=E5=90=88=E3=80=91=E3=80=90Java=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../缺失和重复的元素.md | 30 +++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/高频面试系列/缺失和重复的元素.md b/高频面试系列/缺失和重复的元素.md
index 06e554f..52c8d78 100644
--- a/高频面试系列/缺失和重复的元素.md
+++ b/高频面试系列/缺失和重复的元素.md
@@ -1,4 +1,4 @@
-# 如何寻找缺失和重复的元素
+# 如何寻找缺失和重复的元素
@@ -139,4 +139,30 @@ vector findErrorNums(vector& nums) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[zhuli](https://github.com/1097452462 "zhuli")提供的Java代码:
+```java
+class Solution {
+ public int[] findErrorNums(int[] nums) {
+ int n = nums.length;
+ int dup = -1;
+ for (int i = 0; i < n; i++) {
+ // 元素是从 1 开始的
+ int index = Math.abs(nums[i]) - 1;
+ // nums[index] 小于 0 则说明重复访问
+ if (nums[index] < 0)
+ dup = Math.abs(nums[i]);
+ else
+ nums[index] *= -1;
+ }
+ int missing = -1;
+ for (int i = 0; i < n; i++)
+ // nums[i] 大于 0 则说明没有访问
+ if (nums[i] > 0)
+ // 将索引转换成元素
+ missing = i + 1;
+ return new int[]{dup, missing};
+ }
+}
+```
\ No newline at end of file
From ac37263996303704f162df98bf90358c426bfbef Mon Sep 17 00:00:00 2001
From: Chenjie Xu
Date: Wed, 11 Nov 2020 15:07:41 +0800
Subject: [PATCH 13/63] =?UTF-8?q?=E3=80=9098.=20=E9=AA=8C=E8=AF=81?=
=?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E3=80=91=E3=80=90?=
=?UTF-8?q?Python=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../二叉搜索树操作集锦.md | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/数据结构系列/二叉搜索树操作集锦.md b/数据结构系列/二叉搜索树操作集锦.md
index 6c05626..8281c20 100644
--- a/数据结构系列/二叉搜索树操作集锦.md
+++ b/数据结构系列/二叉搜索树操作集锦.md
@@ -309,3 +309,26 @@ void BST(TreeNode root, int target) {
+
+[ChenjieXu](https://github.com/ChenjieXu)提供第98题Python3代码:
+
+```python
+def isValidBST(self, root):
+ # 递归函数
+ def helper(node, lower = float('-inf'), upper = float('inf')):
+ if not node:
+ return True
+
+ val = node.val
+ if val <= lower or val >= upper:
+ return False
+ # 右节点
+ if not helper(node.right, val, upper):
+ return False
+ # 左节点
+ if not helper(node.left, lower, val):
+ return False
+ return True
+
+ return helper(root)
+```
From 65e137edb75ba5bcbfdf571155c6cf6cbc11863b Mon Sep 17 00:00:00 2001
From: Volvane
Date: Wed, 11 Nov 2020 15:26:31 +0800
Subject: [PATCH 14/63] =?UTF-8?q?Update=20LRU=E7=AE=97=E6=B3=95.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
146题C++代码
---
高频面试系列/LRU算法.md | 88 ++++++++++++++++++++++++++++++++-
1 file changed, 87 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/LRU算法.md b/高频面试系列/LRU算法.md
index b9ca311..23e0b65 100644
--- a/高频面试系列/LRU算法.md
+++ b/高频面试系列/LRU算法.md
@@ -346,4 +346,90 @@ class LRUCache {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[gowufang](https://github.com/gowufang)提供第146题C++代码:
+```cpp
+class LRUCache {
+ public:
+ struct node {
+ int val;
+ int key;
+ node* pre;//当前节点的前一个节点
+ node* next;//当前节点的后一个节点
+ node(){}
+ node(int key, int val):key(key), val(val), pre(NULL), next(NULL){}
+ };
+
+ LRUCache(int size) {
+ this->size = size;
+ head = new node();
+ tail = new node();
+ head->next = tail;
+ tail->pre = head;
+ }
+
+
+ void movetohead(node* cur)//相当于一个insert操作,在head 和 head的next之间插入一个节点
+ {
+ node* next = head->next;//head的next先保存起来
+ head->next = cur;//将当前节点移动到head的后面
+ cur->pre = head;//当前节点cur的pre指向head
+ next->pre = cur;
+ cur->next = next;
+ }
+
+ node* deletecurrentnode(node* cur)//移除当前节点
+ {
+ cur->pre->next = cur->next;
+ cur->next->pre = cur->pre;
+ return cur;
+ }
+ void makerecently(node* cur)
+ {
+ node* temp = deletecurrentnode(cur);// 删除 cur,要重新插入到对头
+ movetohead(temp);//cur放到队头去
+ }
+ int get(int key)
+ {
+ int ret = -1;
+ if ( map.count(key))
+ {
+ node* temp = map[key];
+ makerecently(temp);// 将 key 变为最近使用
+ ret = temp->val;
+ }
+ return ret;
+ }
+
+ void put(int key, int value) {
+ if ( map.count(key))
+ {
+ // 修改 key 的值
+ node* temp = map[key];
+ temp->val = value;
+ // 将 key 变为最近使用
+ makerecently(temp);
+ }
+ else
+ {
+ node* cur = new node(key, value);
+ if( map.size()== size )
+ {
+ // 链表头部就是最久未使用的 key
+ node *temp = deletecurrentnode(tail->pre);
+ map.erase(temp->key);
+ }
+ movetohead(cur);
+ map[key] = cur;
+
+ }
+
+ }
+
+ unordered_map map;
+ int size;
+ node* head, *tail;
+
+ };
+ ```
From 022fe8afccac97df3b5a071799e032a3f1b935f0 Mon Sep 17 00:00:00 2001
From: lixiandea
Date: Wed, 11 Nov 2020 15:37:34 +0800
Subject: [PATCH 15/63] =?UTF-8?q?=E3=80=90100.=20=E7=9B=B8=E5=90=8C?=
=?UTF-8?q?=E7=9A=84=E6=A0=91=E3=80=91=E3=80=90Python=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../二叉搜索树操作集锦.md | 27 ++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/二叉搜索树操作集锦.md b/数据结构系列/二叉搜索树操作集锦.md
index 801b8fb..45b77df 100644
--- a/数据结构系列/二叉搜索树操作集锦.md
+++ b/数据结构系列/二叉搜索树操作集锦.md
@@ -310,4 +310,29 @@ void BST(TreeNode root, int target) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[lixiandea](https://github.com/lixiandea)提供第100题Python3代码:
+```python3
+# Definition for a binary tree node.
+# class TreeNode:
+# def __init__(self, val=0, left=None, right=None):
+# self.val = val
+# self.left = left
+# self.right = right
+class Solution:
+ def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
+ '''
+ 当前节点值相等且树的子树相等,则树相等。
+ 递归退出条件:两个节点存在一个节点为空
+ '''
+ if p == None:
+ if q == None:
+ return True
+ else:
+ return False
+ if q == None:
+ return False
+ # 当前节点相同且左子树和右子树分别相同
+ return p.val==q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
+```
\ No newline at end of file
From ce67219141fbe62377facafe1024a81a3ad3eb85 Mon Sep 17 00:00:00 2001
From: hzs
Date: Wed, 11 Nov 2020 16:03:43 +0800
Subject: [PATCH 16/63] =?UTF-8?q?[239.=E6=BB=91=E5=8A=A8=E7=AA=97=E5=8F=A3?=
=?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=80=BC]=20[Python]?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
数据结构系列/单调队列.md | 50 +++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/单调队列.md b/数据结构系列/单调队列.md
index eb298a1..41b494f 100644
--- a/数据结构系列/单调队列.md
+++ b/数据结构系列/单调队列.md
@@ -210,4 +210,52 @@ vector maxSlidingWindow(vector& nums, int k) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+python3版本
+
+```python
+from collections import deque
+
+class MonotonicQueue(object):
+ def __init__(self):
+ # 双端队列
+ self.data = deque()
+
+ def push(self, n):
+ # 实现单调队列的push方法
+ while self.data and self.data[-1] < n:
+ self.data.pop()
+ self.data.append(n)
+
+ def max(self):
+ # 取得单调队列中的最大值
+ return self.data[0]
+
+ def pop(self, n):
+ # 实现单调队列的pop方法
+ if self.data and self.data[0] == n:
+ self.data.popleft()
+
+
+class Solution:
+ def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
+ # 单调队列实现的窗口
+ window = MonotonicQueue()
+
+ # 结果
+ res = []
+
+ for i in range(0, len(nums)):
+
+ if i < k-1:
+ # 先填满窗口前k-1
+ window.push(nums[i])
+ else:
+ # 窗口向前滑动
+ window.push(nums[i])
+ res.append(window.max())
+ window.pop(nums[i-k+1])
+ return res
+
+```
\ No newline at end of file
From 42845993b606dc6d3b54bcba29e37ee8d26dda48 Mon Sep 17 00:00:00 2001
From: Andrew <920076768@qq.com>
Date: Wed, 11 Nov 2020 16:18:15 +0800
Subject: [PATCH 17/63] =?UTF-8?q?Update=20=E9=80=92=E5=BD=92=E5=8F=8D?=
=?UTF-8?q?=E8=BD=AC=E9=93=BE=E8=A1=A8=E7=9A=84=E4=B8=80=E9=83=A8=E5=88=86?=
=?UTF-8?q?.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
增加了python版本代码
---
.../递归反转链表的一部分.md | 38 ++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/递归反转链表的一部分.md b/数据结构系列/递归反转链表的一部分.md
index 830e503..1f8bca2 100644
--- a/数据结构系列/递归反转链表的一部分.md
+++ b/数据结构系列/递归反转链表的一部分.md
@@ -218,4 +218,40 @@ ListNode reverseBetween(ListNode head, int m, int n) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[DiamondI](https://github.com/DiamondI) 提供python3版本代码:
+
+思路:递归。时间复杂度为O(n),由于递归调用需要借助栈的空间,因此空间复杂度亦为O(n)。
+
+```python3
+# Definition for singly-linked list.
+# class ListNode:
+# def __init__(self, val=0, next=None):
+# self.val = val
+# self.next = next
+class Solution:
+ def __init__(self):
+ self.__successor = None
+
+ def __reverseN(self, head: ListNode, n: int) -> ListNode:
+ if n == 1:
+ # 记录第 n + 1 个节点
+ self.__successor = head.next;
+ return head;
+ # 以 head.next 为起点,需要反转前 n - 1 个节点
+ last = self.__reverseN(head.next, n - 1);
+
+ head.next.next = head;
+ # 让反转之后的 head 节点和后面的节点连起来
+ head.next = self.__successor;
+ return last;
+
+ def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
+ # base case
+ if m == 1:
+ return self.__reverseN(head, n);
+ # 前进到反转的起点触发 base case
+ head.next = self.reverseBetween(head.next, m - 1, n - 1);
+ return head;
+```
From c786b6ab43c7c24e55b4877ea6c1afafae1a2179 Mon Sep 17 00:00:00 2001
From: hzs
Date: Wed, 11 Nov 2020 16:19:53 +0800
Subject: [PATCH 18/63] =?UTF-8?q?=E3=80=90239.=E6=BB=91=E5=8A=A8=E7=AA=97?=
=?UTF-8?q?=E5=8F=A3=E6=9C=80=E5=A4=A7=E5=80=BC=E3=80=91=E3=80=90Python?=
=?UTF-8?q?=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
数据结构系列/单调队列.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/数据结构系列/单调队列.md b/数据结构系列/单调队列.md
index 41b494f..094e510 100644
--- a/数据结构系列/单调队列.md
+++ b/数据结构系列/单调队列.md
@@ -210,10 +210,14 @@ vector maxSlidingWindow(vector& nums, int k) {
+
======其他语言代码======
python3版本
+由[SCUHZS](ttps://github.com/brucecat)提供
+
+
```python
from collections import deque
From 0a4bddfe2b3a540476920d50c17c6457e86344be Mon Sep 17 00:00:00 2001
From: forthespada <44971298+forthespada@users.noreply.github.com>
Date: Wed, 11 Nov 2020 16:21:27 +0800
Subject: [PATCH 19/63] =?UTF-8?q?=E3=80=90234.=E6=BB=91=E5=8A=A8=E7=AA=97?=
=?UTF-8?q?=E5=8F=A3=E6=9C=80=E5=A4=A7=E5=80=BC=E3=80=91=E3=80=90=E5=9B=9E?=
=?UTF-8?q?=E6=96=87=E9=93=BE=E8=A1=A8=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/判断回文链表.md | 33 +++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/判断回文链表.md b/高频面试系列/判断回文链表.md
index 3e24068..4d0225a 100644
--- a/高频面试系列/判断回文链表.md
+++ b/高频面试系列/判断回文链表.md
@@ -237,4 +237,35 @@ p.next = reverse(q);
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+C++版本:
+```cpp
+ bool isPalindrome(ListNode* head) {
+ if (head == nullptr || head->next == nullptr) //为空或者只有一个节点时,直接判断为true
+ return true;
+ ListNode* slow = head, * fast = head;
+ while (fast != nullptr) {//首先找到中间节点
+ slow = slow->next;
+ fast = fast->next == nullptr? fast->next:fast->next->next; //因为链表长度可能是奇数或偶数,所以需要进行判断
+ }
+
+ ListNode* temp = nullptr,* pre = nullptr;//pre始终保持后续链表的头部,temp节点则作为中间零时替换的节点
+ while (slow != nullptr) {//利用头插法,将当前节点与后续链表断链处理,反转后半部分的链表
+ temp = slow->next;
+ slow->next = pre;//建立连接
+ pre = slow;//pre始终作为后续链表的头部
+ slow = temp;
+ }
+
+ while (head !=nullptr && pre != nullptr) {//同步进行比较
+ if (head->val != pre->val) {//值有不一样的,说明不是回文联表,直接返回false了
+ return false;
+ }
+ head = head->next;//head向下走,直到走到空
+ pre = pre->next;//pre节点也向下走,直到走到空
+ }
+ return true;//到此说明当前链表是回文链表返回true即可
+ }
+
+```
From 6b55d3eceb7c3930552126d39e1da2d649493d9f Mon Sep 17 00:00:00 2001
From: Chenjie Xu
Date: Wed, 11 Nov 2020 16:29:21 +0800
Subject: [PATCH 20/63] =?UTF-8?q?=E3=80=9072.=20=E7=BC=96=E8=BE=91?=
=?UTF-8?q?=E8=B7=9D=E7=A6=BB=E3=80=91=E3=80=90Python=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
动态规划系列/编辑距离.md | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/动态规划系列/编辑距离.md b/动态规划系列/编辑距离.md
index 27b8c22..ae6ff4e 100644
--- a/动态规划系列/编辑距离.md
+++ b/动态规划系列/编辑距离.md
@@ -290,3 +290,31 @@ class Node {
+
+[ChenjieXu](https://github.com/ChenjieXu) 提供Python版本代码:
+
+```python3
+def minDistance(word1, word2):
+ m, n = len(word1), len(word2)
+ # 创建 DP 数组
+ dp = [[0] * (n + 1) for _ in range(m + 1)]
+
+ # base case初始化
+ for i in range(m + 1):
+ dp[i][0] = i
+ for j in range(n + 1):
+ dp[0][j] = j
+
+ # 自底向上求解
+ for i in range(1, m + 1):
+ for j in range(1, n + 1):
+ # 状态转移方程
+ if word1[i - 1] == word2[j - 1]:
+ dp[i][j] = dp[i - 1][j - 1]
+ else:
+ dp[i][j] = min(dp[i - 1][j] + 1,
+ dp[i][j - 1] + 1,
+ dp[i - 1][j - 1] + 1)
+ # 储存着整个 word1 和 word2 的最小编辑距离
+ return dp[m][n]
+````
From 701622467245b7b960e57b3d4b1eea1b1b308e90 Mon Sep 17 00:00:00 2001
From: Ed
Date: Wed, 11 Nov 2020 17:08:03 +0800
Subject: [PATCH 21/63] Add 452 python3 version
---
.../贪心算法之区间调度问题.md | 43 ++++++++++++++++++-
1 file changed, 41 insertions(+), 2 deletions(-)
diff --git a/动态规划系列/贪心算法之区间调度问题.md b/动态规划系列/贪心算法之区间调度问题.md
index 70e27fc..8487083 100644
--- a/动态规划系列/贪心算法之区间调度问题.md
+++ b/动态规划系列/贪心算法之区间调度问题.md
@@ -1,4 +1,4 @@
-# 贪心算法之区间调度问题
+# 贪心算法之区间调度问题
@@ -158,4 +158,43 @@ int findMinArrowShots(int[][] intvs) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Edwenc](https://github.com/Edwenc) 提供 第452题的python3 代码:
+
+```python3
+
+class Solution:
+ def findMinArrowShots(self, points: List[List[int]]) -> int:
+ ### 思路是把气球的左右坐标看成是区间
+ ### 用最少数量的箭 相当于 找不重叠区间的个数
+ ### 因为重叠的区间 用一支箭就可以全部引爆气球
+
+ # 首先获得区间的个数 为0的话就不用移除
+ n = len(points)
+ if n==0:
+ return 0
+
+ # 按照每个区间的右端点值进行排序
+ sorted_point = sorted( points , key=lambda x: x[1] )
+
+ # 不重叠区间个数至少是1
+ res = 1
+
+ # end是所有不重叠的区间中 最大的右端点
+ # end的初始值即是sorted_list[0]的右端点
+ end = sorted_point[0][1]
+
+ # 从序号1开始往后找
+ for i in range(1,n):
+ # start是当前区间左端点值
+ start = sorted_point[i][0]
+ # 如果当前左端点比最大右端点都严格大了
+ # 说明两区间严格不重叠 count+1 再更新end
+ if start > end:
+ res += 1
+ end = sorted_point[i][1]
+
+ return res
+
+```
\ No newline at end of file
From 2ce19ed62bce8e79fc9f40b437ae33b3266fc311 Mon Sep 17 00:00:00 2001
From: Ed
Date: Wed, 11 Nov 2020 17:17:08 +0800
Subject: [PATCH 22/63] Add 435 python3 version
---
.../贪心算法之区间调度问题.md | 44 ++++++++++++++++++-
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/动态规划系列/贪心算法之区间调度问题.md b/动态规划系列/贪心算法之区间调度问题.md
index 70e27fc..1865b27 100644
--- a/动态规划系列/贪心算法之区间调度问题.md
+++ b/动态规划系列/贪心算法之区间调度问题.md
@@ -1,4 +1,4 @@
-# 贪心算法之区间调度问题
+# 贪心算法之区间调度问题
@@ -158,4 +158,44 @@ int findMinArrowShots(int[][] intvs) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Edwenc](https://github.com/Edwenc) 提供 第435题的python3 代码:
+
+```python3
+
+class Solution:
+ def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
+ ### 思路是首先找到不重叠的区间的个数
+ ### 然后再用总个数减去不重叠个数
+ ### 获得的就是 需要移除的个数
+
+ # 首先获得区间的个数 为0的话就不用移除
+ n = len(intervals)
+ if n==0:
+ return 0
+
+ # 按照每个区间的右端点值进行排序
+ sorted_list = sorted( intervals , key=lambda x: x[1] )
+
+ # 不重叠区间个数至少是1
+ count = 1
+
+ # end是所有不重叠的区间中 最大的右端点
+ # end的初始值即是sorted_list[0]的右端点
+ end = sorted_list[0][1]
+
+ # 从1开始往后找
+ for i in range(1,n):
+ # start是当前区间左端点值
+ start = sorted_list[i][0]
+ # 如果左端点比右端点都大了(可能相等)
+ # 说明两区间不重叠 count+1 再更新end
+ if start>=end:
+ count += 1
+ end = sorted_list[i][1]
+
+ # 最后返回的是 需要移除的区间个数
+ return n-count
+
+```
\ No newline at end of file
From c09b441ba38c88adc75331087bd76bd4144a4a32 Mon Sep 17 00:00:00 2001
From: Ed
Date: Wed, 11 Nov 2020 17:19:59 +0800
Subject: [PATCH 23/63] A little modification on comment
---
动态规划系列/贪心算法之区间调度问题.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/动态规划系列/贪心算法之区间调度问题.md b/动态规划系列/贪心算法之区间调度问题.md
index 1865b27..05d9502 100644
--- a/动态规划系列/贪心算法之区间调度问题.md
+++ b/动态规划系列/贪心算法之区间调度问题.md
@@ -185,11 +185,11 @@ class Solution:
# end的初始值即是sorted_list[0]的右端点
end = sorted_list[0][1]
- # 从1开始往后找
+ # 从1开始往后找 因为0在上面已经取过了
for i in range(1,n):
# start是当前区间左端点值
start = sorted_list[i][0]
- # 如果左端点比右端点都大了(可能相等)
+ # 如果当前左端点比最大右端点都大了(可能相等)
# 说明两区间不重叠 count+1 再更新end
if start>=end:
count += 1
From b8441fd99e1aca9b2affa9143274d2b215f55a91 Mon Sep 17 00:00:00 2001
From: Zane Wang
Date: Wed, 11 Nov 2020 20:28:34 +1100
Subject: [PATCH 24/63] =?UTF-8?q?=E4=B8=BA=2043-=E5=AD=97=E7=AC=A6?=
=?UTF-8?q?=E4=B8=B2=E4=B9=98=E6=B3=95=20=E6=B7=BB=E5=8A=A0Java=E8=A7=A3?=
=?UTF-8?q?=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/字符串乘法.md | 45 ++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/字符串乘法.md b/算法思维系列/字符串乘法.md
index 0273744..6c7f67d 100644
--- a/算法思维系列/字符串乘法.md
+++ b/算法思维系列/字符串乘法.md
@@ -101,4 +101,47 @@ string multiply(string num1, string num2) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Zane Wang](https://github.com/zanecat) 提供 Java 解法代码:
+```java
+public String multiply(String num1, String num2) {
+ // 初始化字符数组
+ char[] s1 = num1.toCharArray();
+ char[] s2 = num2.toCharArray();
+
+ // 结果长度最多为两字符串长度之和
+ int[] res = new int[s1.length + s2.length];
+
+ // 从个位开始遍历,把两数字中每一位相乘
+ for (int i = s1.length - 1; i >= 0; i--) {
+ for (int j = s2.length - 1; j >= 0; j--) {
+ // 计算乘积,并把乘积放在 res 对应的位置, 暂时不考虑进位
+ res[i + j + 1] += (s1[i] - '0') * (s2[j] - '0');
+ }
+ }
+
+ // 从个位再次遍历,如果上一次遍历中两数乘积为两位数,进位并叠加到前面一位
+ int carry = 0;
+ for (int i = res.length - 1; i >= 0; i--) {
+ int sum = res[i] + carry;
+ res[i] = sum % 10;
+ carry = sum / 10;
+ }
+
+ //遍历res数组,构造最终答案字符串
+ StringBuilder ans = new StringBuilder();
+ int i = 0;
+
+ // 首先找到不为0的第一位
+ while (i < res.length - 1 && res[i] == 0) {
+ i++;
+ }
+
+ // 将后面的数字附加到ans后面
+ while (i < res.length) {
+ ans.append(res[i++]);
+ }
+ return ans.toString();
+}
+```
\ No newline at end of file
From 4e00179e784038b7f9aed3c54be38ee5e2b1b719 Mon Sep 17 00:00:00 2001
From: Ed
Date: Wed, 11 Nov 2020 17:56:09 +0800
Subject: [PATCH 25/63] Add 450 Python3 version
---
.../二叉搜索树操作集锦.md | 56 ++++++++++++++++++-
1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/数据结构系列/二叉搜索树操作集锦.md b/数据结构系列/二叉搜索树操作集锦.md
index 801b8fb..cac9c8c 100644
--- a/数据结构系列/二叉搜索树操作集锦.md
+++ b/数据结构系列/二叉搜索树操作集锦.md
@@ -1,4 +1,4 @@
-# 二叉搜索树操作集锦
+# 二叉搜索树操作集锦
@@ -310,4 +310,56 @@ void BST(TreeNode root, int target) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Edwenc](https://github.com/Edwenc) 提供 leetcode第450题的python3 代码:
+
+```python3
+
+# Definition for a binary tree node.
+# class TreeNode:
+# def __init__(self, val=0, left=None, right=None):
+# self.val = val
+# self.left = left
+# self.right = right
+
+class Solution:
+ def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
+ # 如果没有树 直接返回None
+ if root == None:
+ return None
+
+ # 如果要删除的结点 就是当前结点
+ if root.val == key:
+ # 左子树为空 只有右子树需要被更新 直接返回
+ if root.left == None:
+ return root.right
+ # 右子树为空 只有左子树需要被更新 直接返回
+ if root.right== None:
+ return root.left
+
+ # 找出此结点左子树的最大值
+ # 用这个最大值 来代替当前结点
+ # 再在左子树中递归地删除这个最大值结点
+ big = self.getMax( root.left )
+ root.val = big.val
+ root.left = self.deleteNode( root.left , big.val )
+
+ # 当前结点较大 它的左子树中需要删除节点 递归到左子树
+ elif root.val > key:
+ root.left = self.deleteNode( root.left , key)
+ # 当前结点较小 它的右子树中需要删除节点 递归到右子树
+ else:
+ root.right= self.deleteNode( root.right, key)
+
+ return root
+
+ # 辅助函数
+ # 功能是找出此二叉搜索树中最大元素的结点 并返回此结点
+ def getMax( self , node ):
+ # 一直找它的右子树 直到为空
+ while node.right:
+ node = node.right
+ return node
+
+```
\ No newline at end of file
From 9022e60cd2937dfdf714680b2a57a57c2376aae3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=BD=97=E5=B7=8D=E8=80=80-LWW?= <694125111@qq.com>
Date: Wed, 11 Nov 2020 19:59:07 +0800
Subject: [PATCH 26/63] =?UTF-8?q?Update=20=E7=83=A7=E9=A5=BC=E6=8E=92?=
=?UTF-8?q?=E5=BA=8F.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
新增了Java解决方法
---
算法思维系列/烧饼排序.md | 72 +++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/烧饼排序.md b/算法思维系列/烧饼排序.md
index 513cbdc..cd163bf 100644
--- a/算法思维系列/烧饼排序.md
+++ b/算法思维系列/烧饼排序.md
@@ -149,4 +149,74 @@ void reverse(int[] arr, int i, int j) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[L-WEIWEI](https://github.com/L-WWEEII) 提供 第969题的 Java 代码:
+
+```java
+class Solution {
+ public List pancakeSort(int[] A) {
+ List ans = new ArrayList();
+ int len = A.length;
+ if(len == 0){
+ return ans;
+ }
+ // maxIndex[0] == 当前轮次的最大元素, maxIndex[1] == 最大元素下标
+ int[] maxIndex = new int[2];
+ maxIndex[0] = Integer.MIN_VALUE;
+ int maxCount = 0;
+ // maxCount == len 时,说明完成了整个数组的最大值沉底操作,
+ while(maxCount < len - 1){
+ maxCount = maxValueDown(A, maxIndex, maxCount, ans);
+ // 每做完一次最大值沉底操作,初始化最大元素值
+ maxIndex[0] = Integer.MIN_VALUE;
+ }
+ return ans;
+ }
+ public int maxValueDown(int[] A, int[] maxIndex, int maxCount, List ans){
+ // 遍历条件为 i < A.length - maxCount , 每次最大值沉底时,maxCount + 1,因此下次遍历即可不对最后 maxCount 个元素做操作
+ for(int i = 0; i < A.length - maxCount; i++){
+ // 元素大于当前储存的元素时,将值与下标 copy 到 maxIndex 数组中
+ if(A[i] > maxIndex[0]){
+ maxIndex[0] = A[i];
+ maxIndex[1] = i;
+ }
+ }
+ // 如果当前轮次最大元素的下标的下一位是上一轮次的最大下标,则不做翻转操作,直接返回 maxCount + 1
+ if(maxIndex[1] + 1 == A.length - maxCount){
+ return maxCount + 1;
+ }
+ // 使用最大值沉底时,当本轮最大值在首位时,不需要再将其先翻转至首位,所以不添加
+ if(maxIndex[1] > 0){
+ // 将该轮次要翻转的下标添加到结果集中,结果集中需要的是翻转的位置而不是下标,所以添加时下标得 + 1
+ ans.add(maxIndex[1] + 1);
+ }
+ // 双指针原地交换数组中的值
+ // 左指针指0
+ int left = 0;
+ // 右指针指向当前轮次最大元素的下标
+ int right = maxIndex[1];
+ while(left < right){
+ // 交换元素值
+ A[left] += A[right];
+ A[right] = A[left] - A[right];
+ A[left] -= A[right];
+ left++;
+ right--;
+ }
+ // 上面交换玩元素值后,当前轮次最大元素排在首位,再从上一轮次最大元素 - 1 的位置翻转
+ // 则当前轮次的最大元素成功沉底
+ ans.add(A.length - maxCount);
+ left = 0;
+ right = A.length - 1 - maxCount;
+ while(left < right){
+ A[left] += A[right];
+ A[right] = A[left] - A[right];
+ A[left] -= A[right];
+ left++;
+ right--;
+ }
+ return maxCount + 1;
+ }
+}
+```
From 58ce448d2b64b914373260e3fe0a5b19f69f37d6 Mon Sep 17 00:00:00 2001
From: Hoi Lung Lam
Date: Wed, 11 Nov 2020 23:27:07 +1100
Subject: [PATCH 27/63] Added Python3 code for problem 3.
---
算法思维系列/滑动窗口技巧.md | 29 +++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/滑动窗口技巧.md b/算法思维系列/滑动窗口技巧.md
index e65a104..5d8768b 100644
--- a/算法思维系列/滑动窗口技巧.md
+++ b/算法思维系列/滑动窗口技巧.md
@@ -371,4 +371,31 @@ class Solution:
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+
+
+第3题 Python3 代码(提供: [FaDrYL](https://github.com/FaDrYL) ):
+```Python3
+def lengthOfLongestSubstring(self, s: str) -> int:
+ # 子字符串
+ sub = ""
+ largest = 0
+
+ # 循环字符串,将当前字符加入子字符串,并检查长度
+ for i in range(len(s)):
+ if s[i] not in sub:
+ # 当前字符不存在于子字符串中,加入当前字符
+ sub += s[i]
+ else:
+ # 如果当前子字符串的长度超过了之前的记录
+ if len(sub) > largest:
+ largest = len(sub)
+ # 将子字符串从当前字符处+1切片至最后,并加入当前字符
+ sub = sub[sub.find(s[i])+1:] + s[i]
+
+ # 如果最后的子字符串长度超过了之前的记录
+ if len(sub) > largest:
+ return len(sub)
+ return largest
+```
From d1dcf4cc69efa50cfd78d18481ad41f7646680db Mon Sep 17 00:00:00 2001
From: userLF <1067605626@qq.com>
Date: Wed, 11 Nov 2020 21:00:41 +0800
Subject: [PATCH 28/63] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BA=86=E5=85=A8?=
=?UTF-8?q?=E6=8E=92=E5=88=97=E7=9A=84java=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/子集排列组合.md | 39 +++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/子集排列组合.md b/高频面试系列/子集排列组合.md
index 04fe3bb..bdb6bbe 100644
--- a/高频面试系列/子集排列组合.md
+++ b/高频面试系列/子集排列组合.md
@@ -283,5 +283,42 @@ void backtrack(int[] nums, LinkedList track) {
+======其他语言代码======
-======其他语言代码======
\ No newline at end of file
+[userLF](https://github.com/userLF)提供全排列的java代码:
+
+```java
+import java.util.ArrayList;
+import java.util.List;
+
+class Solution {
+ List> res = new ArrayList<>();
+ public List> permute(int[] nums) {
+ res.clear();
+ dfs(nums, 0);//
+ return res;
+ }
+
+ public void dfs(int[] n, int start) {//start表示要被替换元素的位置
+ if( start >= n.length) {
+ List list = new ArrayList();
+ for(int i : n) {
+ list.add(i);
+ }
+ res.add(list);
+ return;
+ }
+
+ for(int i = start; i< n.length; i++) {//i从start开始,如果从start+1开始的话,会把当前序列遗漏掉直接保存了下一个序列
+ int temp= n[i];
+ n[i] = n[start];
+ n[start] = temp;
+ dfs(n, start + 1);//递归下一个位置
+ //回到上一个状态
+ n[start] = n[i];
+ n[i] = temp;
+ }
+ }
+}
+
+```
\ No newline at end of file
From 13afe04e8345d2fb7876c86f123561fb3ddb4b90 Mon Sep 17 00:00:00 2001
From: cchroot <843328872@qq.com>
Date: Wed, 11 Nov 2020 21:21:20 +0800
Subject: [PATCH 29/63] =?UTF-8?q?=E3=80=90875.=20=E7=88=B1=E5=90=83?=
=?UTF-8?q?=E9=A6=99=E8=95=89=E7=9A=84=E7=8F=82=E7=8F=82=E3=80=91=E3=80=90?=
=?UTF-8?q?C++=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
提供 C++ 解法
---
高频面试系列/koko偷香蕉.md | 35 ++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/koko偷香蕉.md b/高频面试系列/koko偷香蕉.md
index cc880dd..c44f083 100644
--- a/高频面试系列/koko偷香蕉.md
+++ b/高频面试系列/koko偷香蕉.md
@@ -169,4 +169,37 @@ for (int i = 0; i < n; i++)
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[cchroot](https://github.com/cchroot) 提供 C++ 代码:
+
+```c++
+class Solution {
+public:
+ int minEatingSpeed(vector& piles, int H) {
+ // 二分法查找最小速度
+ // 初始化最小速度为 1,最大速度为题目设定的最大值 10^9
+ // 这里也可以遍历 piles 数组,获取数组中的最大值,设置 right 为数组中的最大值即可(因为每堆香蕉1小时吃完是最快的)
+ // log2(10^9) 约等于30,次数不多,所以这里暂时就不采取遍历获取最大值了
+ int left = 1, right = pow(10, 9);
+ while (left < right) { // 二分法基本的防止溢出
+ int mid = left + (right - left) / 2;
+ // 以 mid 的速度吃香蕉,是否能在 H 小时内吃完香蕉
+ if (!canFinish(piles, mid, H))
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ return left;
+ }
+
+ // 以 speed 的速度是否能把香蕉吃完
+ bool canFinish(vector& piles, int speed, int H) {
+ int time = 0;
+ // 遍历累加时间 time
+ for (int p: piles)
+ time += (p - 1) / speed + 1;
+ return time <= H; // time 小于等于 H 说明能在 H 小时吃完返回 true, 否则返回 false
+ }
+};
+```
From df9116647912d3a84ced39794a85384f100ba8bc Mon Sep 17 00:00:00 2001
From: LEO D PEN <33611404+LEODPEN@users.noreply.github.com>
Date: Wed, 11 Nov 2020 21:25:36 +0800
Subject: [PATCH 30/63] =?UTF-8?q?leodpen=20Union-Find=E7=AE=97?=
=?UTF-8?q?=E6=B3=95=E5=BA=94=E7=94=A8.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/UnionFind算法应用.md | 78 ++++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/UnionFind算法应用.md b/算法思维系列/UnionFind算法应用.md
index fef484a..c1af151 100644
--- a/算法思维系列/UnionFind算法应用.md
+++ b/算法思维系列/UnionFind算法应用.md
@@ -20,6 +20,8 @@
[990.等式方程的可满足性](https://leetcode-cn.com/problems/surrounded-regions)
+[261.以图判树](https://leetcode-cn.com/problems/graph-valid-tree/)
+
**-----------**
上篇文章很多读者对于 Union-Find 算法的应用表示很感兴趣,这篇文章就拿几道 LeetCode 题目来讲讲这个算法的巧妙用法。
@@ -250,4 +252,78 @@ boolean equationsPossible(String[] equations) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+第261题的Java代码(提供:[LEODPEN](https://github.com/LEODPEN))
+
+```java
+class Solution {
+
+ class DisjointSet {
+
+ int count; // 连通分量的总个数
+ int[] parent; // 每个节点的头节点(不一定是连通分量的最终头节点)
+ int[] size; // 每个连通分量的大小
+
+ public DisjointSet(int n) {
+ parent = new int[n];
+ size = new int[n];
+ // 初为n个连通分量,期望最后为1
+ count = n;
+ for (int i = 0; i < n; i++) {
+ // 初始的连通分量只有该节点本身
+ parent[i] = i;
+ size[i] = 1;
+ }
+ }
+
+ /**
+ * @param first 节点1
+ * @param second 节点2
+ * @return 未连通 && 连通成功
+ */
+ public boolean union(int first, int second) {
+ // 分别找到包含first 和 second 的最终根节点
+ int firstParent = findRootParent(first), secondParent = findRootParent(second);
+ // 相等说明已经处于一个连通分量,即说明有环
+ if (firstParent == secondParent) return false;
+ // 将较小的连通分量融入较大的连通分量
+ if (size[firstParent] >= size[secondParent]) {
+ parent[secondParent] = firstParent;
+ size[firstParent] += size[secondParent];
+ } else {
+ parent[firstParent] = secondParent;
+ size[secondParent] += size[firstParent];
+ }
+ // 连通分量已合并,count减少
+ count--;
+ return true;
+ }
+
+ /**
+ * @param node 某节点
+ * @return 包含该节点的连通分量的最终根节点
+ */
+ private int findRootParent(int node) {
+ while (node != parent[node]) {
+ // 压缩路径
+ parent[node] = parent[parent[node]];
+ node = parent[node];
+ }
+ return node;
+ }
+ }
+
+ public boolean validTree(int n, int[][] edges) {
+ // 树的特性:节点数 = 边数 + 1
+ if (edges.length != n - 1) return false;
+ graph_261.Solution.DisjointSet djs = new graph_261.Solution.DisjointSet(n);
+ for (int[] edg : edges) {
+ // 判断连通情况(如果合并的两个点在一个连通分量里,说明有环)
+ if (!djs.union(edg[0], edg[1])) return false;
+ }
+ // 是否全部节点均已相连
+ return djs.count == 1;
+ }
+}
+```
From b946853ee8479241f349c721ac15c6922fc4879d Mon Sep 17 00:00:00 2001
From: cchroot <843328872@qq.com>
Date: Wed, 11 Nov 2020 21:30:17 +0800
Subject: [PATCH 31/63] =?UTF-8?q?=E3=80=905.=20=E6=9C=80=E9=95=BF=E5=9B=9E?=
=?UTF-8?q?=E6=96=87=E5=AD=90=E4=B8=B2=E3=80=91=E3=80=90Java=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
提供 Java 代码
---
高频面试系列/最长回文子串.md | 38 +++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/最长回文子串.md b/高频面试系列/最长回文子串.md
index 9f0f37f..d69b65e 100644
--- a/高频面试系列/最长回文子串.md
+++ b/高频面试系列/最长回文子串.md
@@ -131,4 +131,40 @@ string longestPalindrome(string s) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[cchromt](https://github.com/cchroot) 提供 Java 代码:
+
+```java
+// 中心扩展算法
+class Solution {
+ public String longestPalindrome(String s) {
+ // 如果字符串长度小于2,则直接返回其本身
+ if (s.length() < 2) {
+ return s;
+ }
+ String res = "";
+ for (int i = 0; i < s.length() - 1; i++) {
+ // 以 s.charAt(i) 为中心的最长回文子串
+ String s1 = palindrome(s, i, i);
+ // 以 s.charAt(i) 和 s.charAt(i+1) 为中心的最长回文子串
+ String s2 = palindrome(s, i, i + 1);
+ res = res.length() > s1.length() ? res : s1;
+ res = res.length() > s2.length() ? res : s2;
+ }
+ return res;
+ }
+
+ public String palindrome(String s, int left, int right) {
+ // 索引未越界的情况下,s.charAt(left) == s.charAt(right) 则继续向两边拓展
+ while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
+ left--;
+ right++;
+ }
+ // 这里要注意,跳出 while 循环时,恰好满足 s.charAt(i) != s.charAt(j),因此截取的的字符串为[left+1, right-1]
+ return s.substring(left + 1, right);
+ }
+}
+```
+
+做完这题,大家可以去看看 [647. 回文子串](https://leetcode-cn.com/problems/palindromic-substrings/) ,也是类似的题目
From 6f708d5b98f7d72411e0b0ec4c555c4f1584eefb Mon Sep 17 00:00:00 2001
From: ZSZ2018211261 <2955324023@qq.com>
Date: Wed, 11 Nov 2020 22:35:43 +0800
Subject: [PATCH 32/63] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20=E3=80=9056.=20?=
=?UTF-8?q?=E5=90=88=E5=B9=B6=E5=8C=BA=E9=97=B4=E3=80=91=E3=80=90java?=
=?UTF-8?q?=E3=80=91=E9=A2=98=E8=A7=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../区间调度问题之区间合并.md | 63 ++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/区间调度问题之区间合并.md b/算法思维系列/区间调度问题之区间合并.md
index e4ca2dc..7972184 100644
--- a/算法思维系列/区间调度问题之区间合并.md
+++ b/算法思维系列/区间调度问题之区间合并.md
@@ -90,5 +90,66 @@ def merge(intervals):
+======其他语言代码======
+
+~~~java
+class Solution {
+ /**
+ * 1. 先对区间集合进行排序(根据开始位置)
+ * 2. 合并的情况一共有三种
+ * a. b. c.
+ * |---------| |--------| |--------|
+ * |---------| |--| |--------|
+ * a和b两种情况,合并取右边界大的值,c情况不合并
+ *
+ */
+
+ private int[][] tmp;
+
+ public int[][] merge(int[][] intervals) {
+ if(intervals == null ||intervals.length == 0)return new int[0][0];
+ int length = intervals.length;
+ //将列表中的区间按照左端点升序排序
+ // Arrays.sort(intervals,(v1,v2) -> v1[0]-v2[0]);
+
+ this.tmp = new int[length][2];
+ sort(intervals,0,length-1);
+
+ int[][] ans = new int[length][2];
+ int index = -1;
+ for(int[] interval:intervals){
+ // 当结果数组是空是,或者当前区间的起始位置 > 结果数组中最后区间的终止位置(即上图情况c);
+ // 则不合并,直接将当前区间加入结果数组。
+ if(index == -1 || interval[0] > ans[index][1]){
+ ans[++index] = interval;
+ }else{
+ // 反之将当前区间合并至结果数组的最后区间(即上图情况a,b)
+ ans[index][1] = Math.max(ans[index][1],interval[1]);
+ }
+ }
+ return Arrays.copyOf(ans, index + 1);
+ }
+
+ //归并排序
+ public void sort(int[][] intervals,int l,int r){
+ if(l >= r)return;
+
+ int mid = l + (r-l)/2;
+ sort(intervals,l,mid);
+ sort(intervals,mid+1,r);
+
+ //合并
+ int i=l,j=mid+1;
+ for(int k=l;k<=r;k++){
+ if(i>mid)tmp[k]=intervals[j++];
+ else if(j>r)tmp[k]=intervals[i++];
+ else if(intervals[i][0]>intervals[j][0])tmp[k] = intervals[j++];
+ else tmp[k] = intervals[i++];
+ }
+
+ System.arraycopy(tmp,l,intervals,l,r-l+1);
+ }
+
+}
+~~~
-======其他语言代码======
\ No newline at end of file
From 97e5e1dee3df464f7deb181fba4139442d77ad26 Mon Sep 17 00:00:00 2001
From: hzs
Date: Wed, 11 Nov 2020 17:44:49 +0800
Subject: [PATCH 33/63] =?UTF-8?q?=E3=80=90877.=E7=9F=B3=E5=AD=90=E6=B8=B8?=
=?UTF-8?q?=E6=88=8F=E3=80=90Python=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../动态规划之博弈问题.md | 55 ++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/动态规划之博弈问题.md b/动态规划系列/动态规划之博弈问题.md
index 9f52fa4..c85c100 100644
--- a/动态规划系列/动态规划之博弈问题.md
+++ b/动态规划系列/动态规划之博弈问题.md
@@ -215,4 +215,57 @@ int stoneGame(int[] piles) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+
+
+
+
+python3版本
+
+由[SCUHZS](https://github.com/brucecat)提供
+
+这里采取的是三维的做法
+
+```python
+class Solution:
+ def stoneGame(self, piles: List[int]) -> bool:
+ n = len(piles)
+
+ # 初始化一个n*n的矩阵 dp数组
+ dp = [[None] * n for i in range(0, n)]
+
+ # 在三角区域填充
+ for i in range(n):
+ for j in range(i, n):
+ dp[i][j] = [0, 0]
+
+ # 填入base case
+ for i in range(0, n):
+ dp[i][i][0] = piles[i]
+ dp[i][i][1] = 0
+
+ # 斜着遍历数组
+ for l in range(2, n + 1):
+ for i in range(0, n-l+1):
+ j = l + i - 1
+
+
+ # 先手选择最左边或最右边的分数
+ left = piles[i] + dp[i + 1][j][1]
+ right = piles[j] + dp[i][j - 1][1]
+
+ # 套用状态转移方程
+ if left > right:
+ dp[i][j][0] = left
+ dp[i][j][1] = dp[i + 1][j][0]
+ else:
+ dp[i][j][0] = right
+ dp[i][j][1] = dp[i][j - 1][0]
+
+ res = dp[0][n - 1]
+
+ return res[0] - res[1] > 0
+
+```
+
From bc14b2e06201be75cf4a28b8d463e8e1f83f6608 Mon Sep 17 00:00:00 2001
From: hzs
Date: Wed, 11 Nov 2020 17:50:05 +0800
Subject: [PATCH 34/63] =?UTF-8?q?=E3=80=90877.=E7=9F=B3=E5=AD=90=E6=B8=B8?=
=?UTF-8?q?=E6=88=8F=E3=80=90Python=E3=80=91=E4=B8=80=E7=BB=B4dp?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../动态规划之博弈问题.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/动态规划系列/动态规划之博弈问题.md b/动态规划系列/动态规划之博弈问题.md
index c85c100..90615ba 100644
--- a/动态规划系列/动态规划之博弈问题.md
+++ b/动态规划系列/动态规划之博弈问题.md
@@ -269,3 +269,21 @@ class Solution:
```
+
+
+压缩成一维数组,以减小空间复杂度,做法如下。
+
+```python
+class Solution:
+ def stoneGame(self, piles: List[int]) -> bool:
+ dp = piles.copy()
+
+ for i in range(len(piles) - 1, -1, -1): # 从下往上遍历
+ for j in range(i, len(piles)): # 从前往后遍历
+ dp[j] = max(piles[i] - dp[j], piles[j] - dp[j - 1]) # 计算之后覆盖一维数组的对应位置
+
+ return dp[len(piles) - 1] > 0
+
+
+```
+
From 36f59b6fe9ee832a7896e405c8bb76ae62b31e99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=BD=97=E5=B7=8D=E8=80=80-LWW?= <694125111@qq.com>
Date: Wed, 11 Nov 2020 22:27:58 +0800
Subject: [PATCH 35/63] =?UTF-8?q?Update=20=E6=89=93=E5=8D=B0=E7=B4=A0?=
=?UTF-8?q?=E6=95=B0.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
增加了C++版本的代码
---
高频面试系列/打印素数.md | 39 +++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/打印素数.md b/高频面试系列/打印素数.md
index 2ab9e10..3a58074 100644
--- a/高频面试系列/打印素数.md
+++ b/高频面试系列/打印素数.md
@@ -178,4 +178,41 @@ int countPrimes(int n) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+C++解法:
+采用的算法是埃拉托斯特尼筛法
+埃拉托斯特尼筛法的具体内容就是:**要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。**
+同时考虑到大于2的偶数都不是素数,所以可以进一步优化成:**要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的奇数倍剔除,剩下的奇数就是素数。**
+此算法其实就是上面的Java解法所采用的。
+
+这里提供C++的代码:
+```C++
+class Solution {
+public:
+ int countPrimes(int n) {
+ int res = 0;
+ bool prime[n+1];
+ for(int i = 0; i < n; ++i)
+ prime[i] = true;
+
+ for(int i = 2; i <= sqrt(n); ++i) //计数过程
+ { //外循环优化,因为判断一个数是否为质数只需要整除到sqrt(n),反推亦然
+ if(prime[i])
+ {
+ for(int j = i * i; j < n; j += i) //内循环优化,i*i之前的比如i*2,i*3等,在之前的循环中已经验证了
+ {
+ prime[j] = false;
+ }
+ }
+ }
+ for (int i = 2; i < n; ++i)
+ if (prime[i]) res++; //最后遍历统计一遍,存入res
+
+ return res;
+ }
+};
+```
+
+
+
From 6860be44b844b4147d68bb5501af87a59d390061 Mon Sep 17 00:00:00 2001
From: "shuhaofeng2@creditease.cn"
Date: Wed, 11 Nov 2020 23:21:14 +0800
Subject: [PATCH 36/63] =?UTF-8?q?feat:=20=E4=B8=BA=2043-=E5=AD=97=E7=AC=A6?=
=?UTF-8?q?=E4=B8=B2=E4=B9=98=E6=B3=95=20=E6=B7=BB=E5=8A=A0python=E8=A7=A3?=
=?UTF-8?q?=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
feat: 为 43-字符串乘法 添加python解法1
feat: 为 43-字符串乘法 添加python解法3
---
算法思维系列/字符串乘法.md | 31 ++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/字符串乘法.md b/算法思维系列/字符串乘法.md
index 0273744..8349f7a 100644
--- a/算法思维系列/字符串乘法.md
+++ b/算法思维系列/字符串乘法.md
@@ -101,4 +101,33 @@ string multiply(string num1, string num2) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[fengshuu](https://github.com/fengshuu) 提供 Python 解法代码:
+```python
+def multiply(num1: str, num2: str) -> str:
+ m, n = len(num1), len(num2)
+ # 结果最多为 m + n 位数
+ res = [0] * (m + n)
+ # 从个位数开始逐位相乘
+ for i in range(m-1, -1, -1):
+ for j in range(n-1, -1, -1):
+ mul = int(num1[i]) * int(num2[j])
+ # 乘积在 res 对应的索引位置
+ p1 = i + j
+ p2 = i + j + 1
+ # 叠加到 res 上
+ digit_sum = mul + res[p2]
+ res[p2] = digit_sum % 10
+ res[p1] += digit_sum // 10
+
+ # 结果前缀可能存的 0(未使用的位)
+ i = 0
+ while i < len(res) and res[i] == 0:
+ i += 1
+
+ # 将计算结果转化成字符串
+ result_str = "".join(str(x) for x in res[i:])
+
+ return "0" if len(result_str) == 0 else result_str
+```
\ No newline at end of file
From edb2084f07cc23a9df50655da1c93dd690930dff Mon Sep 17 00:00:00 2001
From: zak
Date: Wed, 11 Nov 2020 23:55:46 +0800
Subject: [PATCH 37/63] =?UTF-8?q?=E3=80=90496.=E4=B8=8B=E4=B8=80=E4=B8=AA?=
=?UTF-8?q?=E6=9B=B4=E5=A4=A7=E5=85=83=E7=B4=A0I=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
数据结构系列/单调栈.md | 56 ++++++++++++++++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/单调栈.md b/数据结构系列/单调栈.md
index fca0ca8..961e810 100644
--- a/数据结构系列/单调栈.md
+++ b/数据结构系列/单调栈.md
@@ -181,4 +181,58 @@ vector nextGreaterElements(vector& nums) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[ZakAnun](https://github.com/ZakAnun) 提供代码
+
+```java
+// 496.下一个更大元素
+// 暴力解法
+public int[] nextGreaterElement(int[] nums1, int[] nums2) {
+ int[] result = new int[nums1.length];
+ for (int i = 0; i < nums1.length; i++) {
+ // 需要记录第一个数组每个元素在第二个数组中出现的位置
+ int index = 0;
+ for (int j = 0; j < nums2.length; j++) {
+ if (nums1[i] == nums2[j]) {
+ index = j;
+ break;
+ }
+ }
+ // 根据找到的位置往后遍历,若符合条件则记录到结果数组
+ for (int k = index; k < nums2.length; k++) {
+ if (nums2[k] > nums1[i]) {
+ result[i] = nums2[k];
+ break;
+ }
+ }
+ // 判断若对应位置结果依然为默认值,则将其修改为 -1
+ if (result[i] == 0) {
+ result[i] = -1;
+ }
+ }
+ return result;
+}
+
+// 分析: 暴力解法中需要确定数组1中每个元素在数组2中的下标而需要进行额外的遍历导致时间复杂度升高,
+// 但若能够先罗列出全部的结果,然后从结果集中获取数组1中每个元素对应的下一个更大元素,就可以节省这部分时间(这里需要引用 HashMap 帮助我们记录结果,以便根据数组1获取。
+// 单调栈解法
+public int[] nextGreaterElement(int[] nums1, int[] nums2) {
+ Stack stack = new Stack <>();
+ HashMap map = new HashMap <>();
+ int[] result = new int[nums1.length];
+ for (int value : nums2) {
+ while (!stack.empty() && value > stack.peek()) {
+ map.put(stack.pop(), value);
+ }
+ stack.push(value);
+ }
+ while (!stack.empty()) {
+ map.put(stack.pop(), -1);
+ }
+ for (int i = 0; i < nums1.length; i++) {
+ result[i] = map.get(nums1[i]);
+ }
+ return result;
+}
+```
\ No newline at end of file
From 9519492a8b9b9971a301be53dd006af09ba0689c Mon Sep 17 00:00:00 2001
From: "shuhaofeng2@creditease.cn"
Date: Thu, 12 Nov 2020 00:45:38 +0800
Subject: [PATCH 38/63] =?UTF-8?q?feat:=20=E3=80=90969.=20=E7=85=8E?=
=?UTF-8?q?=E9=A5=BC=E6=8E=92=E5=BA=8F=E3=80=91=E3=80=90C++=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/烧饼排序.md | 45 +++++++++++++++++++++++++++++-
1 file changed, 44 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/烧饼排序.md b/算法思维系列/烧饼排序.md
index 513cbdc..5b9bf5d 100644
--- a/算法思维系列/烧饼排序.md
+++ b/算法思维系列/烧饼排序.md
@@ -149,4 +149,47 @@ void reverse(int[] arr, int i, int j) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[fengshuu](https://github.com/fengshuu) 提供 C++ 解法代码:
+```cpp
+class Solution {
+public:
+ vector pancakeSort(vector& arr) {
+ sort(arr, arr.size());
+ return res;
+ }
+
+private:
+ // 记录反转操作序列
+ vector res;
+ void sort(vector& cakes, int n){
+ // base case
+ if(n == 1) return;
+
+ // 寻找最大饼的索引
+ int maxCakeIndex = max_element(cakes.begin(), cakes.begin() + n) - cakes.begin();
+
+ // 下面进行把最大的饼放到最后的两次翻转
+ // 如果最后一个饼就是最大的, 就不需要翻转, 直接进行下次递归
+ if (maxCakeIndex == n-1){
+ sort(cakes, n - 1);
+ return;
+ }
+
+ // 第一次翻转, 将最大饼翻到最上面
+ // 如果第一个饼本来就是最大的, 就不需要第一次翻转.
+ if (maxCakeIndex != 0) {
+ reverse(cakes.begin(), cakes.begin() + maxCakeIndex + 1);
+ res.push_back(maxCakeIndex + 1);
+ }
+
+ // 第二次翻转,将最大饼翻到最下面
+ reverse(cakes.begin(), cakes.begin() + n);
+ res.push_back(n);
+
+ // 递归调用
+ sort(cakes, n - 1);
+ }
+};
+```
\ No newline at end of file
From aa25e0d36c303bf49a93e27a2401f457edd6a4d8 Mon Sep 17 00:00:00 2001
From: "shuhaofeng2@creditease.cn"
Date: Thu, 12 Nov 2020 00:55:23 +0800
Subject: [PATCH 39/63] =?UTF-8?q?feat:=20=E3=80=90969.=20=E7=85=8E?=
=?UTF-8?q?=E9=A5=BC=E6=8E=92=E5=BA=8F=E3=80=91=E3=80=90C++=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/烧饼排序.md | 62 +++++++++++++++---------------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/算法思维系列/烧饼排序.md b/算法思维系列/烧饼排序.md
index 5b9bf5d..c9e191d 100644
--- a/算法思维系列/烧饼排序.md
+++ b/算法思维系列/烧饼排序.md
@@ -157,39 +157,39 @@ class Solution {
public:
vector pancakeSort(vector& arr) {
sort(arr, arr.size());
- return res;
+ return res;
}
-
+
private:
- // 记录反转操作序列
+ // 记录反转操作序列
vector res;
- void sort(vector& cakes, int n){
- // base case
- if(n == 1) return;
-
- // 寻找最大饼的索引
- int maxCakeIndex = max_element(cakes.begin(), cakes.begin() + n) - cakes.begin();
-
- // 下面进行把最大的饼放到最后的两次翻转
- // 如果最后一个饼就是最大的, 就不需要翻转, 直接进行下次递归
- if (maxCakeIndex == n-1){
- sort(cakes, n - 1);
- return;
- }
-
- // 第一次翻转, 将最大饼翻到最上面
- // 如果第一个饼本来就是最大的, 就不需要第一次翻转.
- if (maxCakeIndex != 0) {
- reverse(cakes.begin(), cakes.begin() + maxCakeIndex + 1);
- res.push_back(maxCakeIndex + 1);
- }
-
- // 第二次翻转,将最大饼翻到最下面
- reverse(cakes.begin(), cakes.begin() + n);
- res.push_back(n);
-
- // 递归调用
- sort(cakes, n - 1);
- }
+ void sort(vector& cakes, int n){
+ // base case
+ if(n == 1) return;
+
+ // 寻找最大饼的索引
+ int maxCakeIndex = max_element(cakes.begin(), cakes.begin() + n) - cakes.begin();
+
+ // 下面进行把最大的饼放到最后的两次翻转
+ // 如果最后一个饼就是最大的, 就不需要翻转, 直接进行下次递归
+ if (maxCakeIndex == n-1){
+ sort(cakes, n - 1);
+ return;
+ }
+
+ // 第一次翻转, 将最大饼翻到最上面
+ // 如果第一个饼本来就是最大的, 就不需要第一次翻转.
+ if (maxCakeIndex != 0) {
+ reverse(cakes.begin(), cakes.begin() + maxCakeIndex + 1);
+ res.push_back(maxCakeIndex + 1);
+ }
+
+ // 第二次翻转,将最大饼翻到最下面
+ reverse(cakes.begin(), cakes.begin() + n);
+ res.push_back(n);
+
+ // 递归调用
+ sort(cakes, n - 1);
+ }
};
```
\ No newline at end of file
From dd5749bb3bd66898ca6a06aec00da281e9dfd87f Mon Sep 17 00:00:00 2001
From: "shuhaofeng2@creditease.cn"
Date: Thu, 12 Nov 2020 01:23:59 +0800
Subject: [PATCH 40/63] =?UTF-8?q?feat:=20=E3=80=90969.=20=E7=85=8E?=
=?UTF-8?q?=E9=A5=BC=E6=8E=92=E5=BA=8F=E3=80=91=E3=80=90Python3=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/烧饼排序.md | 39 +++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/烧饼排序.md b/算法思维系列/烧饼排序.md
index 513cbdc..67604ae 100644
--- a/算法思维系列/烧饼排序.md
+++ b/算法思维系列/烧饼排序.md
@@ -149,4 +149,41 @@ void reverse(int[] arr, int i, int j) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[fengshuu](https://github.com/fengshuu) 提供 Python3 解法代码:
+```python
+class Solution:
+ # 记录反转操作序列
+ def __init__(self):
+ self.res = []
+
+ def pancakeSort(self, arr: List[int]) -> List[int]:
+
+ self.sort(arr, len(arr))
+ return self.res
+
+ def sort(self, cakes: List[int], n: int):
+ # base case
+ if 1 == n:
+ return
+
+ # 寻找最大饼的索引
+ max_cake_index = cakes[:n].index(n)
+
+ # 下面进行把最大的饼放到最后的两次翻转
+ # 如果最后一个饼就是最大的, 就不需要翻转, 直接进行下次递归
+ if max_cake_index != n - 1:
+ # 第一次翻转, 将最大饼翻到最上面
+ # 如果第一个饼本来就是最大的, 就不需要第一次翻转.
+ if max_cake_index != 0:
+ cakes[:max_cake_index + 1] = cakes[:max_cake_index + 1][::-1]
+ self.res.append(max_cake_index + 1)
+
+ # 第二次翻转,将最大饼翻到最下面
+ cakes[:n] = cakes[:n][::-1]
+ self.res.append(n)
+
+ # 递归调用
+ self.sort(cakes, n - 1)
+```
\ No newline at end of file
From 8a2f374f63d568d3e45d99a6c0c4466d399ea2d5 Mon Sep 17 00:00:00 2001
From: "ningwei.shi"
Date: Thu, 12 Nov 2020 09:21:54 +0800
Subject: [PATCH 41/63] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
动态规划系列/抢房子.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/动态规划系列/抢房子.md b/动态规划系列/抢房子.md
index d2c3f0f..081c583 100644
--- a/动态规划系列/抢房子.md
+++ b/动态规划系列/抢房子.md
@@ -311,7 +311,9 @@ class Solution:
left = dp(root.left)
right = dp(root.right)
+ # 抢当前,则两个下家不抢
do = root.val + left[0] + right[0]
+ # 不抢当前,则下家随意
do_not = max(left) + max(right)
return do_not, do
From d5b5f57380cf6a3f047a29253e811a10e5dcb498 Mon Sep 17 00:00:00 2001
From: LEO D PEN
Date: Thu, 12 Nov 2020 12:00:29 +0800
Subject: [PATCH 42/63] =?UTF-8?q?Update=20UnionFind=E7=AE=97=E6=B3=95?=
=?UTF-8?q?=E5=BA=94=E7=94=A8.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/UnionFind算法应用.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/算法思维系列/UnionFind算法应用.md b/算法思维系列/UnionFind算法应用.md
index c1af151..c3ce82f 100644
--- a/算法思维系列/UnionFind算法应用.md
+++ b/算法思维系列/UnionFind算法应用.md
@@ -317,7 +317,7 @@ class Solution {
public boolean validTree(int n, int[][] edges) {
// 树的特性:节点数 = 边数 + 1
if (edges.length != n - 1) return false;
- graph_261.Solution.DisjointSet djs = new graph_261.Solution.DisjointSet(n);
+ DisjointSet djs = new DisjointSet(n);
for (int[] edg : edges) {
// 判断连通情况(如果合并的两个点在一个连通分量里,说明有环)
if (!djs.union(edg[0], edg[1])) return false;
From 6294fbcb734ad5f79bfa10ef46610f2f7e19f4d1 Mon Sep 17 00:00:00 2001
From: labuladong
Date: Thu, 12 Nov 2020 14:26:22 +0800
Subject: [PATCH 43/63] fixurl
---
动态规划系列/动态规划之博弈问题.md | 2 +-
.../动态规划设计:最长递增子序列.md | 10 +++++-----
动态规划系列/团灭股票问题.md | 4 ++--
动态规划系列/最优子结构.md | 2 +-
动态规划系列/高楼扔鸡蛋问题.md | 2 +-
算法思维系列/滑动窗口技巧.md | 4 ++--
6 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/动态规划系列/动态规划之博弈问题.md b/动态规划系列/动态规划之博弈问题.md
index 90615ba..44246ab 100644
--- a/动态规划系列/动态规划之博弈问题.md
+++ b/动态规划系列/动态规划之博弈问题.md
@@ -22,7 +22,7 @@
上一篇文章 [几道智力题](https://labuladong.gitbook.io/algo) 中讨论到一个有趣的「石头游戏」,通过题目的限制条件,这个游戏是先手必胜的。但是智力题终究是智力题,真正的算法问题肯定不会是投机取巧能搞定的。所以,本文就借石头游戏来讲讲「假设两个人都足够聪明,最后谁会获胜」这一类问题该如何用动态规划算法解决。
-博弈类问题的套路都差不多,下文举例讲解,其核心思路是在二维 dp 的基础上使用元组分别存储两个人的博弈结果。掌握了这个技巧以后,别人再问你什么俩海盗分宝石,俩人拿硬币的问题,你就告诉别人:我懒得想,直接给你写个算法算一下得了。
+博弈类问题的套路都差不多,下文参考 [这个 YouTube 视频](https://www.youtube.com/watch?v=WxpIHvsu1RI) 的思路讲解,其核心思路是在二维 dp 的基础上使用元组分别存储两个人的博弈结果。掌握了这个技巧以后,别人再问你什么俩海盗分宝石,俩人拿硬币的问题,你就告诉别人:我懒得想,直接给你写个算法算一下得了。
我们「石头游戏」改的更具有一般性:
diff --git a/动态规划系列/动态规划设计:最长递增子序列.md b/动态规划系列/动态规划设计:最长递增子序列.md
index c905a60..4613f84 100644
--- a/动态规划系列/动态规划设计:最长递增子序列.md
+++ b/动态规划系列/动态规划设计:最长递增子序列.md
@@ -10,8 +10,8 @@

相关推荐:
- * [动态规划设计:最大子数组](../动态规划系列/最大子数组.md)
- * [一文学会递归解题](../投稿/一文学会递归解题.md)
+ * [动态规划设计:最大子数组](https://labuladong.gitbook.io/algo)
+ * [一文学会递归解题](https://labuladong.gitbook.io/algo)
读完本文,你不仅学会了算法套路,还可以顺便去 LeetCode 上拿下如下题目:
@@ -19,7 +19,7 @@
**-----------**
-也许有读者看了前文 [动态规划详解](../动态规划系列/动态规划详解进阶.md),学会了动态规划的套路:找到了问题的「状态」,明确了 `dp` 数组/函数的含义,定义了 base case;但是不知道如何确定「选择」,也就是不到状态转移的关系,依然写不出动态规划解法,怎么办?
+也许有读者看了前文 [动态规划详解](https://labuladong.gitbook.io/algo),学会了动态规划的套路:找到了问题的「状态」,明确了 `dp` 数组/函数的含义,定义了 base case;但是不知道如何确定「选择」,也就是不到状态转移的关系,依然写不出动态规划解法,怎么办?
不要担心,动态规划的难点本来就在于寻找正确的状态转移方程,本文就借助经典的「最长递增子序列问题」来讲一讲设计动态规划的通用技巧:**数学归纳思想**。
@@ -43,7 +43,7 @@
**我们的定义是这样的:`dp[i]` 表示以 `nums[i]` 这个数结尾的最长递增子序列的长度。**
-PS:为什么这样定义呢?这是解决子序列问题的一个套路,后文[动态规划之子序列问题解题模板](../动态规划系列/子序列问题模板.md) 总结了几种常见套路。你读完本章所有的动态规划问题,就会发现 `dp` 数组的定义方法也就那几种。
+PS:为什么这样定义呢?这是解决子序列问题的一个套路,后文[动态规划之子序列问题解题模板](https://labuladong.gitbook.io/algo) 总结了几种常见套路。你读完本章所有的动态规划问题,就会发现 `dp` 数组的定义方法也就那几种。
根据这个定义,我们就可以推出 base case:`dp[i]` 初始值为 1,因为以 `nums[i]` 结尾的最长递增子序列起码要包含它自己。
@@ -164,7 +164,7 @@ public int lengthOfLIS(int[] nums) {
我们只要把处理扑克牌的过程编程写出来即可。每次处理一张扑克牌不是要找一个合适的牌堆顶来放吗,牌堆顶的牌不是**有序**吗,这就能用到二分查找了:用二分查找来搜索当前牌应放置的位置。
-PS:旧文[二分查找算法详解](../算法思维系列/二分查找详解.md)详细介绍了二分查找的细节及变体,这里就完美应用上了,如果没读过强烈建议阅读。
+PS:旧文[二分查找算法详解](https://labuladong.gitbook.io/algo)详细介绍了二分查找的细节及变体,这里就完美应用上了,如果没读过强烈建议阅读。
```java
public int lengthOfLIS(int[] nums) {
diff --git a/动态规划系列/团灭股票问题.md b/动态规划系列/团灭股票问题.md
index be2b463..61f64a3 100644
--- a/动态规划系列/团灭股票问题.md
+++ b/动态规划系列/团灭股票问题.md
@@ -16,7 +16,7 @@
读完本文,你不仅学会了算法套路,还可以顺便去 LeetCode 上拿下如下题目:
-[买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/)
+[买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock)
[买卖股票的最佳时机 II](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)
@@ -32,7 +32,7 @@
很多读者抱怨 LeetCode 的股票系列问题奇技淫巧太多,如果面试真的遇到这类问题,基本不会想到那些巧妙的办法,怎么办?**所以本文拒绝奇技淫巧,而是稳扎稳打,只用一种通用方法解决所用问题,以不变应万变**。
-这篇文章用状态机的技巧来解决,可以全部提交通过。不要觉得这个名词高大上,文学词汇而已,实际上就是 DP table,看一眼就明白了。
+这篇文章参考 [英文版高赞题解](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/discuss/108870/Most-consistent-ways-of-dealing-with-the-series-of-stock-problems) 的思路,用状态机的技巧来解决,可以全部提交通过。不要觉得这个名词高大上,文学词汇而已,实际上就是 DP table,看一眼就明白了。
先随便抽出一道题,看看别人的解法:
diff --git a/动态规划系列/最优子结构.md b/动态规划系列/最优子结构.md
index 2dc21f2..caf68cf 100644
--- a/动态规划系列/最优子结构.md
+++ b/动态规划系列/最优子结构.md
@@ -54,7 +54,7 @@ return result;
当然,上面这个例子太简单了,不过请读者回顾一下,我们做动态规划问题,是不是一直在求各种最值,本质跟我们举的例子没啥区别,无非需要处理一下重叠子问题。
-前文不[同定义不同解法](../动态规划系列/动态规划之四键键盘.md) 和 [高楼扔鸡蛋进阶](../动态规划系列/高楼扔鸡蛋问题.md) 就展示了如何改造问题,不同的最优子结构,可能导致不同的解法和效率。
+前文不[同定义不同解法](https://labuladong.gitbook.io/algo) 和 [高楼扔鸡蛋进阶](https://labuladong.gitbook.io/algo) 就展示了如何改造问题,不同的最优子结构,可能导致不同的解法和效率。
再举个常见但也十分简单的例子,求一棵二叉树的最大值,不难吧(简单起见,假设节点中的值都是非负数):
diff --git a/动态规划系列/高楼扔鸡蛋问题.md b/动态规划系列/高楼扔鸡蛋问题.md
index 70c63a0..68bd9b8 100644
--- a/动态规划系列/高楼扔鸡蛋问题.md
+++ b/动态规划系列/高楼扔鸡蛋问题.md
@@ -243,7 +243,7 @@ def superEggDrop(self, K: int, N: int) -> int:
return dp(K, N)
```
-这里就不展开其他解法了,留在下一篇文章 [高楼扔鸡蛋进阶](../动态规划系列/高楼扔鸡蛋进阶.md)
+这里就不展开其他解法了,留在下一篇文章 [高楼扔鸡蛋进阶](https://labuladong.gitbook.io/algo)
我觉得吧,我们这种解法就够了:找状态,做选择,足够清晰易懂,可流程化,可举一反三。掌握这套框架学有余力的话,再去考虑那些奇技淫巧也不迟。
diff --git a/算法思维系列/滑动窗口技巧.md b/算法思维系列/滑动窗口技巧.md
index e65a104..67e6539 100644
--- a/算法思维系列/滑动窗口技巧.md
+++ b/算法思维系列/滑动窗口技巧.md
@@ -12,8 +12,8 @@
**最新消息:关注公众号参与活动,有机会成为 [70k star 算法仓库](https://github.com/labuladong/fucking-algorithm) 的贡献者,机不可失时不再来**!
相关推荐:
-* [东哥吃葡萄时竟然吃出一道算法题!](../高频面试系列/吃葡萄.md)
-* [如何寻找缺失的元素](../高频面试系列/消失的元素.md)
+* [东哥吃葡萄时竟然吃出一道算法题!](https://labuladong.gitbook.io/algo)
+* [如何寻找缺失的元素](https://labuladong.gitbook.io/algo)
读完本文,你不仅学会了算法套路,还可以顺便去 LeetCode 上拿下如下题目:
From 4591b795796a287b76cf340adc1e69d1c10066d2 Mon Sep 17 00:00:00 2001
From: HuangXiao
Date: Wed, 11 Nov 2020 11:51:34 +0800
Subject: [PATCH 44/63] Add java code for LCS
---
动态规划系列/最长公共子序列.md | 27 ++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/最长公共子序列.md b/动态规划系列/最长公共子序列.md
index bee8947..39b13dd 100644
--- a/动态规划系列/最长公共子序列.md
+++ b/动态规划系列/最长公共子序列.md
@@ -147,4 +147,29 @@ else:
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Shawn](https://github.com/Shawn-Hx) 提供 Java 代码:
+
+```java
+public int longestCommonSubsequence(String text1, String text2) {
+ // 字符串转为char数组以加快访问速度
+ char[] str1 = text1.toCharArray();
+ char[] str2 = text2.toCharArray();
+
+ int m = str1.length, n = str2.length;
+ // 构建dp table,初始值默认为0
+ int[][] dp = new int[m + 1][n + 1];
+ // 状态转移
+ for (int i = 1; i <= m; i++)
+ for (int j = 1; j <= n; j++)
+ if (str1[i - 1] == str2[j - 1])
+ // 找到LCS中的字符
+ dp[i][j] = dp[i-1][j-1] + 1;
+ else
+ dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
+
+ return dp[m][n];
+}
+```
+
From 4d4a55f28ed891e8c98db8bb593ae54acf6d33cf Mon Sep 17 00:00:00 2001
From: Kian Kwok
Date: Wed, 11 Nov 2020 11:37:25 +0800
Subject: [PATCH 45/63] =?UTF-8?q?Update=20=E5=8A=A8=E6=80=81=E8=A7=84?=
=?UTF-8?q?=E5=88=92=E8=AE=BE=E8=AE=A1=EF=BC=9A=E6=9C=80=E9=95=BF=E9=80=92?=
=?UTF-8?q?=E5=A2=9E=E5=AD=90=E5=BA=8F=E5=88=97.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
create problem-300 c++
---
...态规划设计:最长递增子序列.md | 43 ++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/动态规划设计:最长递增子序列.md b/动态规划系列/动态规划设计:最长递增子序列.md
index 4613f84..a2a0460 100644
--- a/动态规划系列/动态规划设计:最长递增子序列.md
+++ b/动态规划系列/动态规划设计:最长递增子序列.md
@@ -215,4 +215,45 @@ public int lengthOfLIS(int[] nums) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Kian](https://github.com/KianKw/) 提供 C++ 代码
+
+```c++
+class Solution {
+public:
+ int lengthOfLIS(vector& nums) {
+ /* len 为牌的数量 */
+ int len = nums.size();
+ vector top(len, 0);
+ /* 牌堆数初始化为0 */
+ int piles = 0;
+ for (int i = 0; i < len; i++) {
+ /* nums[i] 为要处理的扑克牌 */
+ int poker = nums[i];
+
+ /***** 搜索左侧边界的二分查找 *****/
+ int left = 0, right = piles;
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+ if (top[mid] > poker) {
+ right = mid;
+ } else if (top[mid] < poker) {
+ left = mid + 1;
+ } else if (top[mid] == poker) {
+ right = mid;
+ }
+ }
+ /*********************************/
+
+ /* 没找到合适的牌堆,新建一堆 */
+ if (left == piles)
+ piles++;
+ /* 把这张牌放到牌堆顶 */
+ top[left] = poker;
+ }
+ /* 牌堆数就是 LIS 长度 */
+ return piles;
+ }
+};
+```
From 8473c84f8d9207882efed9b45fdb5b1ac6153564 Mon Sep 17 00:00:00 2001
From: Lu Zhao
Date: Tue, 10 Nov 2020 20:00:07 -0800
Subject: [PATCH 46/63] add 20 java
---
高频面试系列/合法括号判定.md | 26 +++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/合法括号判定.md b/高频面试系列/合法括号判定.md
index 32239bd..3bded5a 100644
--- a/高频面试系列/合法括号判定.md
+++ b/高频面试系列/合法括号判定.md
@@ -112,4 +112,28 @@ char leftOf(char c) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+```java
+//基本思想:每次遇到左括号时都将相对应的右括号')',']'或'}'推入堆栈
+//如果在字符串中出现右括号,则需要检查堆栈是否为空,以及顶部元素是否与该右括号相同。如果不是,则该字符串无效。
+//最后,我们还需要检查堆栈是否为空
+public boolean isValid(String s) {
+ Deque stack = new ArrayDeque<>();
+ for(char c : s.toCharArray()){
+ //是左括号就将相对应的右括号入栈
+ if(c=='(') {
+ stack.offerLast(')');
+ }else if(c=='{'){
+ stack.offerLast('}');
+ }else if(c=='['){
+ stack.offerLast(']');
+ }else if(stack.isEmpty() || stack.pollLast()!=c){//出现右括号,检查堆栈是否为空,以及顶部元素是否与该右括号相同
+ return false;
+ }
+ }
+ return stack.isEmpty();
+}
+
+```
+
From 780a1c46612684861613925295117ea7f85307b8 Mon Sep 17 00:00:00 2001
From: Ryan Deng
Date: Tue, 10 Nov 2020 22:58:31 -0500
Subject: [PATCH 47/63] =?UTF-8?q?=E3=80=90141.=E7=8E=AF=E5=BD=A2=E9=93=BE?=
=?UTF-8?q?=E8=A1=A8=E3=80=91=E3=80=90Python=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
算法思维系列/双指针技巧.md | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/算法思维系列/双指针技巧.md b/算法思维系列/双指针技巧.md
index cf5227d..f5edbd4 100644
--- a/算法思维系列/双指针技巧.md
+++ b/算法思维系列/双指针技巧.md
@@ -230,4 +230,25 @@ void reverse(int[] nums) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[ryandeng32](https://github.com/ryandeng32/) 提供 Python 代码
+```python
+class Solution:
+ def hasCycle(self, head: ListNode) -> bool:
+ # 检查链表头是否为None,是的话则不可能为环形
+ if head is None:
+ return False
+ # 快慢指针初始化
+ slow = fast = head
+ # 若链表非环形则快指针终究会遇到None,然后退出循环
+ while fast.next and fast.next.next:
+ # 更新快慢指针
+ slow = slow.next
+ fast = fast.next.next
+ # 快指针追上慢指针则链表为环形
+ if slow == fast:
+ return True
+ # 退出循环,则链表有结束,不可能为环形
+ return False
+```
From 513fac4f4b9a44a71159118be5df08fa59c56245 Mon Sep 17 00:00:00 2001
From: FrankHui <757583912@qq.com>
Date: Wed, 11 Nov 2020 12:54:40 +0800
Subject: [PATCH 48/63] =?UTF-8?q?=E3=80=90146.=20LRU=E7=BC=93=E5=AD=98?=
=?UTF-8?q?=E6=9C=BA=E5=88=B6=E3=80=91=E3=80=90=20python3=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
python3版本的LRU缓存机制
---
高频面试系列/LRU算法.md | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/LRU算法.md b/高频面试系列/LRU算法.md
index b9ca311..04ebea8 100644
--- a/高频面试系列/LRU算法.md
+++ b/高频面试系列/LRU算法.md
@@ -346,4 +346,34 @@ class LRUCache {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+```python3
+"""
+所谓LRU缓存,根本的难点在于记录最久被使用的键值对,这就设计到排序的问题,
+在python中,天生具备排序功能的字典就是OrderDict。
+注意到,记录最久未被使用的键值对的充要条件是将每一次put/get的键值对都定义为
+最近访问,那么最久未被使用的键值对自然就会排到最后。
+如果你深入python OrderDict的底层实现,就会知道它的本质是个双向链表+字典。
+它内置支持了
+1. move_to_end来重排链表顺序,它可以让我们将最近访问的键值对放到最后面
+2. popitem来弹出键值对,它既可以弹出最近的,也可以弹出最远的,弹出最远的就是我们要的操作。
+"""
+from collections import OrderedDict
+class LRUCache:
+ def __init__(self, capacity: int):
+ self.capacity = capacity # cache的容量
+ self.visited = OrderedDict() # python内置的OrderDict具备排序的功能
+ def get(self, key: int) -> int:
+ if key not in self.visited:
+ return -1
+ self.visited.move_to_end(key) # 最近访问的放到链表最后,维护好顺序
+ return self.visited[key]
+ def put(self, key: int, value: int) -> None:
+ if key not in self.visited and len(self.visited) == self.capacity:
+ # last=False时,按照FIFO顺序弹出键值对
+ # 因为我们将最近访问的放到最后,所以最远访问的就是最前的,也就是最first的,故要用FIFO顺序
+ self.visited.popitem(last=False)
+ self.visited[key]=value
+ self.visited.move_to_end(key) # 最近访问的放到链表最后,维护好顺序
+
+```
From 372b92bf7cd5bbbb00c96717806bed7f254da655 Mon Sep 17 00:00:00 2001
From: dekunma <53892579+dekunma@users.noreply.github.com>
Date: Wed, 11 Nov 2020 14:21:23 +0800
Subject: [PATCH 49/63] =?UTF-8?q?=E3=80=9098.=20=E9=AA=8C=E8=AF=81?=
=?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E3=80=91=E3=80=90?=
=?UTF-8?q?C++=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../二叉搜索树操作集锦.md | 34 ++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/数据结构系列/二叉搜索树操作集锦.md b/数据结构系列/二叉搜索树操作集锦.md
index 801b8fb..b30ceeb 100644
--- a/数据结构系列/二叉搜索树操作集锦.md
+++ b/数据结构系列/二叉搜索树操作集锦.md
@@ -310,4 +310,36 @@ void BST(TreeNode root, int target) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+[dekunma](https://www.linkedin.com/in/dekun-ma-036a9b198/)提供第98题C++代码:
+```C++
+/**
+ * Definition for a binary tree node.
+ * struct TreeNode {
+ * int val;
+ * TreeNode *left;
+ * TreeNode *right;
+ * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
+ * };
+ */
+class Solution {
+public:
+ bool isValidBST(TreeNode* root) {
+ // 用helper method求解
+ return isValidBST(root, nullptr, nullptr);
+ }
+
+ bool isValidBST(TreeNode* root, TreeNode* min, TreeNode* max) {
+ // base case, root为nullptr
+ if (!root) return true;
+
+ // 不符合BST的条件
+ if (min && root->val <= min->val) return false;
+ if (max && root->val >= max->val) return false;
+
+ // 向左右子树分别递归求解
+ return isValidBST(root->left, min, root)
+ && isValidBST(root->right, root, max);
+ }
+};
+```
From 3360ffda0fd458460a9c4908a0d7c0c58f539373 Mon Sep 17 00:00:00 2001
From: dragon_li <49151509+1097452462@users.noreply.github.com>
Date: Thu, 12 Nov 2020 20:13:10 +0800
Subject: [PATCH 50/63] =?UTF-8?q?Update=20=E7=BC=BA=E5=A4=B1=E5=92=8C?=
=?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=9A=84=E5=85=83=E7=B4=A0.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/缺失和重复的元素.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/高频面试系列/缺失和重复的元素.md b/高频面试系列/缺失和重复的元素.md
index 52c8d78..9e0b550 100644
--- a/高频面试系列/缺失和重复的元素.md
+++ b/高频面试系列/缺失和重复的元素.md
@@ -1,4 +1,4 @@
-# 如何寻找缺失和重复的元素
+# 如何寻找缺失和重复的元素
@@ -165,4 +165,4 @@ class Solution {
return new int[]{dup, missing};
}
}
-```
\ No newline at end of file
+```
From 1b2ec335ea4b1ae65ba4cb1e92ff2b9e318b1084 Mon Sep 17 00:00:00 2001
From: dragon_li <49151509+1097452462@users.noreply.github.com>
Date: Thu, 12 Nov 2020 20:15:23 +0800
Subject: [PATCH 51/63] =?UTF-8?q?Update=20=E7=BC=BA=E5=A4=B1=E5=92=8C?=
=?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=9A=84=E5=85=83=E7=B4=A0.md?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/缺失和重复的元素.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/高频面试系列/缺失和重复的元素.md b/高频面试系列/缺失和重复的元素.md
index 9e0b550..eb21f4c 100644
--- a/高频面试系列/缺失和重复的元素.md
+++ b/高频面试系列/缺失和重复的元素.md
@@ -148,7 +148,7 @@ class Solution {
int n = nums.length;
int dup = -1;
for (int i = 0; i < n; i++) {
- // 元素是从 1 开始的
+ // 元素是从 1 开始的
int index = Math.abs(nums[i]) - 1;
// nums[index] 小于 0 则说明重复访问
if (nums[index] < 0)
@@ -160,7 +160,7 @@ class Solution {
for (int i = 0; i < n; i++)
// nums[i] 大于 0 则说明没有访问
if (nums[i] > 0)
- // 将索引转换成元素
+ // 将索引转换成元素
missing = i + 1;
return new int[]{dup, missing};
}
From 12fbf2910a9a99b5adcbe95f54787295e57d0bb3 Mon Sep 17 00:00:00 2001
From: ruiboliu
Date: Tue, 10 Nov 2020 23:06:18 -0500
Subject: [PATCH 52/63] =?UTF-8?q?509=20=E6=96=90=E6=B3=A2=E9=82=A3?=
=?UTF-8?q?=E5=A5=91=E6=95=B0=E5=88=97=20Python=203=20=E8=A7=A3=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../动态规划详解进阶.md | 43 ++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/动态规划详解进阶.md b/动态规划系列/动态规划详解进阶.md
index bff29f4..8ec424b 100644
--- a/动态规划系列/动态规划详解进阶.md
+++ b/动态规划系列/动态规划详解进阶.md
@@ -366,4 +366,45 @@ PS:为啥 `dp` 数组初始化为 `amount + 1` 呢,因为凑成 `amount` 金
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[DapangLiu](https://github.com/DapangLiu) 提供 509. 斐波那契数 Python3 解法代码:
+
+递归写法
+
+```python
+class Solution:
+ def fib(self, N: int) -> int:
+ if N <= 1:
+ return N
+ return self.fib(N-1) + self.fib(N-2)
+```
+
+动态规划写法
+
+```python
+class Solution:
+ def fib(self, N: int) -> int:
+ if N == 0:
+ return 0
+ # init
+ result = [0 for i in range(N+1)]
+ result[1] = 1
+
+ # status transition
+ for j in range(2, N+1):
+ result[j] = result[j-1] + result[j-2]
+ return result[-1]
+```
+
+动态规划写法 (状态压缩)
+
+```python
+class Solution:
+ def fib(self, n: int) -> int:
+ # current status only depends on two previous status
+ dp_0, dp_1 = 0, 1
+ for _ in range(n):
+ dp_0, dp_1 = dp_1, dp_0 + dp_1
+ return dp_0
+```
\ No newline at end of file
From 0ad9a50f645ff6328ea89fdd668bd1f8263dca2b Mon Sep 17 00:00:00 2001
From: Edwenc <45341488+Edwenc@users.noreply.github.com>
Date: Tue, 17 Nov 2020 17:35:19 +0800
Subject: [PATCH 53/63] =?UTF-8?q?=E3=80=901143.=E6=9C=80=E9=95=BF=E5=85=AC?=
=?UTF-8?q?=E5=85=B1=E5=AD=90=E5=BA=8F=E5=88=97=E3=80=91=E3=80=90C++=20?=
=?UTF-8?q?=E3=80=91=20(#500)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* add 1143 C++ version
* add comment
Co-authored-by: Ed
Co-authored-by: labuladong
---
动态规划系列/最长公共子序列.md | 37 ++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/最长公共子序列.md b/动态规划系列/最长公共子序列.md
index 39b13dd..bff1721 100644
--- a/动态规划系列/最长公共子序列.md
+++ b/动态规划系列/最长公共子序列.md
@@ -1,4 +1,4 @@
-# 最长公共子序列
+# 最长公共子序列
@@ -149,6 +149,40 @@ else:
======其他语言代码======
+
+[Edwenc](https://github.com/Edwenc) 提供 C++ 代码:
+
+```C++
+class Solution {
+public:
+ int longestCommonSubsequence(string text1, string text2) {
+ // 先计算两条字符串的长度
+ int m = text1.size();
+ int n = text2.size();
+
+ // 构建dp矩阵 默认初始值0
+ // 这里会多扩建一边和一列
+ // 因为dp[i][j]的含义是:对于 s1[1..i] 和 s2[1..j],它们的LCS长度是 dp[i][j]。
+ // 所以当i或者j为零时 LCS的长度默认为0
+ vector< vector > dp ( m+1 , vector ( n+1 , 0 ) );
+
+ // 状态转移
+ // i、j都从1开始遍历 因为下面的操作中都会-1 相当于从0开始
+ for ( int i=1 ; i
Date: Tue, 10 Nov 2020 23:35:50 -0500
Subject: [PATCH 54/63] =?UTF-8?q?=E3=80=9042.=20=E6=8E=A5=E9=9B=A8?=
=?UTF-8?q?=E6=B0=B4=E3=80=91=E3=80=90Java=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
高频面试系列/接雨水.md | 97 ++++++++++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/高频面试系列/接雨水.md b/高频面试系列/接雨水.md
index e1fd625..a500aac 100644
--- a/高频面试系列/接雨水.md
+++ b/高频面试系列/接雨水.md
@@ -211,4 +211,99 @@ if (l_max < r_max) {
-======其他语言代码======
\ No newline at end of file
+======其他语言代码======
+
+[Yifan Zhang](https://github.com/FanFan0919) 提供 java 代码
+
+**双指针解法**:时间复杂度 O(N),空间复杂度 O(1)
+
+对cpp版本的解法有非常微小的优化。
+因为我们每次循环只会选 left 或者 right 处的柱子来计算,因此我们并不需要在每次循环中同时更新`maxLeft`和`maxRight`。
+我们可以先比较 `maxLeft` 和 `maxRight`,决定这次选择计算的柱子是 `height[left]` 或者 `height[right]` 后再更新对应的 `maxLeft` 或 `maxRight`。
+当然这并不会在时间上带来什么优化,只是提供一种思路。
+
+```java
+class Solution {
+ public int trap(int[] height) {
+ if (height == null || height.length == 0) return 0;
+ int left = 0, right = height.length - 1;
+ int maxLeft = height[left], maxRight = height[right];
+ int res = 0;
+
+ while (left < right) {
+ // 比较 maxLeft 和 maxRight,决定这次计算 left 还是 right 处的柱子
+ if (maxLeft < maxRight) {
+ left++;
+ maxLeft = Math.max(maxLeft, height[left]); // update maxLeft
+ res += maxLeft - height[left];
+ } else {
+ right--;
+ maxRight = Math.max(maxRight, height[right]); // update maxRight
+ res += maxRight - height[right];
+ }
+ }
+
+ return res;
+ }
+}
+```
+
+附上暴力解法以及备忘录解法的 java 代码
+
+**暴力解法**:时间复杂度 O(N^2),空间复杂度 O(1)
+```java
+class Solution {
+ public int trap(int[] height) {
+ if (height == null || height.length == 0) return 0;
+ int n = height.length;
+ int res = 0;
+ // 跳过最左边和最右边的柱子,从第二个柱子开始
+ for (int i = 1; i < n - 1; i++) {
+ int maxLeft = 0, maxRight = 0;
+ // 找右边最高的柱子
+ for (int j = i; j < n; j++) {
+ maxRight = Math.max(maxRight, height[j]);
+ }
+ // 找左边最高的柱子
+ for (int j = i; j >= 0; j--) {
+ maxLeft = Math.max(maxLeft, height[j]);
+ }
+ // 如果自己就是最高的话,
+ // maxLeft == maxRight == height[i]
+ res += Math.min(maxLeft, maxRight) - height[i];
+ }
+ return res;
+ }
+}
+```
+
+**备忘录解法**:时间复杂度 O(N),空间复杂度 O(N)
+```java
+class Solution {
+ public int trap(int[] height) {
+ if (height == null || height.length == 0) return 0;
+ int n = height.length;
+ int res = 0;
+ // 数组充当备忘录
+ int[] maxLeft = new int[n];
+ int[] maxRight = new int[n];
+ // 初始化 base case
+ maxLeft[0] = height[0];
+ maxRight[n - 1] = height[n - 1];
+
+ // 从左向右计算 maxLeft
+ for (int i = 1; i < n; i++) {
+ maxLeft[i] = Math.max(maxLeft[i - 1], height[i]);
+ }
+ // 从右向左计算 maxRight
+ for (int i = n - 2; i >= 0; i--) {
+ maxRight[i] = Math.max(maxRight[i + 1], height[i]);
+ }
+ // 计算答案
+ for (int i = 1; i < n; i++) {
+ res += Math.min(maxLeft[i], maxRight[i]) - height[i];
+ }
+ return res;
+ }
+}
+```
\ No newline at end of file
From 424f210d1560b0e16c46b83d34db65cc5cfa3120 Mon Sep 17 00:00:00 2001
From: Skylar Liang <31715464+SkylarLJY@users.noreply.github.com>
Date: Tue, 17 Nov 2020 17:37:35 +0800
Subject: [PATCH 55/63] 20 Valid Parentheses python3 (#502)
Co-authored-by: labuladong
---
高频面试系列/合法括号判定.md | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/高频面试系列/合法括号判定.md b/高频面试系列/合法括号判定.md
index 3bded5a..6516aa1 100644
--- a/高频面试系列/合法括号判定.md
+++ b/高频面试系列/合法括号判定.md
@@ -114,6 +114,28 @@ char leftOf(char c) {
======其他语言代码======
+### Python3
+```python
+def isValid(self, s: str) -> bool:
+ left = []
+ leftOf = {
+ ')':'(',
+ ']':'[',
+ '}':'{'
+ }
+ for c in s:
+ if c in '([{':
+ left.append(c)
+ elif left and leftOf[c]==left[-1]: # 右括号 + left不为空 + 和最近左括号能匹配
+ left.pop()
+ else: # 右括号 + (left为空 / 和堆顶括号不匹配)
+ return False
+
+ # left中所有左括号都被匹配则return True 反之False
+ return not left
+```
+
+
```java
//基本思想:每次遇到左括号时都将相对应的右括号')',']'或'}'推入堆栈
//如果在字符串中出现右括号,则需要检查堆栈是否为空,以及顶部元素是否与该右括号相同。如果不是,则该字符串无效。
@@ -137,3 +159,4 @@ public boolean isValid(String s) {
```
+
From 7b6cab8386033457eaabc41a35e160ef0035fdf7 Mon Sep 17 00:00:00 2001
From: SherlockGuo <38394051+SherlockGuo@users.noreply.github.com>
Date: Tue, 17 Nov 2020 17:49:13 +0800
Subject: [PATCH 56/63] =?UTF-8?q?=E3=80=90300.=E6=9C=80=E9=95=BF=E4=B8=8A?=
=?UTF-8?q?=E5=8D=87=E5=AD=90=E5=BA=8F=E5=88=97=E3=80=91=E3=80=90Python?=
=?UTF-8?q?=E3=80=91=20(#507)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* add python
* add python
* add python
Co-authored-by: LockyGuo
Co-authored-by: labuladong
---
...态规划设计:最长递增子序列.md | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/动态规划系列/动态规划设计:最长递增子序列.md b/动态规划系列/动态规划设计:最长递增子序列.md
index a2a0460..edef473 100644
--- a/动态规划系列/动态规划设计:最长递增子序列.md
+++ b/动态规划系列/动态规划设计:最长递增子序列.md
@@ -217,6 +217,51 @@ public int lengthOfLIS(int[] nums) {
======其他语言代码======
+```python 动态规划
+class Solution:
+ def lengthOfLIS(self, nums: List[int]) -> int:
+ n = len(nums)
+ f = [1] * (n)
+
+ for i in range(n):
+ for j in range(i):
+ if nums[j] < nums[i]:
+ f[i] = max(f[i], f[j] + 1)
+
+ res = 0
+ for i in range(n):
+ res = max(res, f[i])
+ return res
+```
+
+```python 二分查找
+class Solution:
+ def lengthOfLIS(self, nums: List[int]) -> int:
+ stack = []
+
+ def find_index(num):
+ l, r = 0, len(stack)
+ while l < r:
+ mid = l + r >> 1
+ if stack[mid] >= num:
+ r = mid
+ else:
+ l = mid + 1
+
+ return r
+
+
+ for num in nums:
+ if not stack or num > stack[-1]:
+ stack.append(num)
+ else:
+ position = find_index(num)
+ stack[position] = num
+
+ return len(stack)
+```
+
+
[Kian](https://github.com/KianKw/) 提供 C++ 代码
```c++
@@ -257,3 +302,4 @@ public:
}
};
```
+
From 85301014bb879a33327dfa6643466c0184dd14c7 Mon Sep 17 00:00:00 2001
From: TCeason <33082201+TCeason@users.noreply.github.com>
Date: Tue, 17 Nov 2020 17:56:31 +0800
Subject: [PATCH 57/63] add a cpp hash map version for stoneGame (#599)
---
.../动态规划之博弈问题.md | 43 ++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/动态规划系列/动态规划之博弈问题.md b/动态规划系列/动态规划之博弈问题.md
index 44246ab..f9082d8 100644
--- a/动态规划系列/动态规划之博弈问题.md
+++ b/动态规划系列/动态规划之博弈问题.md
@@ -221,7 +221,7 @@ int stoneGame(int[] piles) {
-python3版本
+* python3版本
由[SCUHZS](https://github.com/brucecat)提供
@@ -287,3 +287,44 @@ class Solution:
```
+* C++ 版本
+
+由 [TCeason](https://github.com/TCeason) 提供
+
+这里采用 hash map 来解决问题
+
+```cpp
+class Solution {
+public:
+ unordered_map memo;
+
+ int dfs(vector &piles, int index) {
+ // 从两边向中间获取
+ // index 值为 1/2 piles.size() 时可以停止算法
+ if (index == piles.size() / 2)
+ return 0;
+
+ // 减少计算,快速返回已有结果
+ if (memo.count(index))
+ return memo[index];
+
+ // 防止第一次取最右时越界
+ int n = piles.size() - 1;
+
+ // 先手选择最左边或最右边后的分数
+ int l = piles[index] + dfs(piles, index + 1);
+ int r = piles[n - index] + dfs(piles, index + 1);
+
+ // 返回先手左或右边的最高分
+ return memo[index] = max(l, r);
+ }
+
+ bool stoneGame(vector& piles) {
+ // 最佳发挥时:
+ // 先手得分 * 2 > 总大小 则先手者胜利
+ return dfs(piles, 0) * 2 > accumulate(begin(piles), end(piles), 0);
+ }
+};
+
+```
+
From 560ea5d9b9ac6fa3b5d8f82697871464c8784fb0 Mon Sep 17 00:00:00 2001
From: labuladong
Date: Tue, 17 Nov 2020 19:14:05 +0800
Subject: [PATCH 58/63] =?UTF-8?q?=E6=90=9C=E4=B8=80=E6=90=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index c969002..45995ef 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ English version repo and Gitbook is on [english branch](https://github.com/labul
+
+
From 0b2efdc76576cce2b03971eceed00cba79765d48 Mon Sep 17 00:00:00 2001
From: labuladong
Date: Wed, 18 Nov 2020 11:19:47 +0800
Subject: [PATCH 59/63] fixbug
---
动态规划系列/动态规划详解进阶.md | 4 +++-
数据结构系列/单调栈.md | 6 +++---
算法思维系列/二分查找详解.md | 4 ++--
算法思维系列/双指针技巧.md | 7 ++++++-
4 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/动态规划系列/动态规划详解进阶.md b/动态规划系列/动态规划详解进阶.md
index 8ec424b..f51608e 100644
--- a/动态规划系列/动态规划详解进阶.md
+++ b/动态规划系列/动态规划详解进阶.md
@@ -146,6 +146,8 @@ int helper(vector& memo, int n) {
```cpp
int fib(int N) {
+ if (N == 0) return 0;
+ if (N == 1) return 1;
vector dp(N + 1, 0);
// base case
dp[1] = dp[2] = 1;
@@ -200,7 +202,7 @@ int coinChange(int[] coins, int amount);
比如说 `k = 3`,面值分别为 1,2,5,总金额 `amount = 11`。那么最少需要 3 枚硬币凑出,即 11 = 5 + 5 + 1。
-你认为计算机应该如何解决这个问题?显然,就是把所有肯能的凑硬币方法都穷举出来,然后找找看最少需要多少枚硬币。
+你认为计算机应该如何解决这个问题?显然,就是把所有可能的凑硬币方法都穷举出来,然后找找看最少需要多少枚硬币。
**1、暴力递归**
diff --git a/数据结构系列/单调栈.md b/数据结构系列/单调栈.md
index fca0ca8..5cbdc4e 100644
--- a/数据结构系列/单调栈.md
+++ b/数据结构系列/单调栈.md
@@ -11,7 +11,7 @@

相关推荐:
- * [回溯算法解题套路框架](https://labuladong.gitbook.io/algo)
+* [回溯算法解题套路框架](https://labuladong.gitbook.io/algo)
* [动态规划解题套路框架](https://labuladong.gitbook.io/algo)
读完本文,你不仅学会了算法套路,还可以顺便去 LeetCode 上拿下如下题目:
@@ -20,7 +20,7 @@
[503.下一个更大元素II](https://leetcode-cn.com/problems/next-greater-element-ii)
-[1118.一月有多少天](https://leetcode-cn.com/problems/number-of-days-in-a-month)
+[739.每日温度](https://leetcode-cn.com/problems/daily-temperatures/)
**-----------**
@@ -82,7 +82,7 @@ vector nextGreaterElement(vector& nums) {
### 问题变形
-单调栈的使用技巧差不多了,来一个简单的变形,力扣第 1118 题「一月有多少天」:
+单调栈的使用技巧差不多了,来一个简单的变形,力扣第 739 题「每日温度」:
给你一个数组 `T`,这个数组存放的是近几天的天气气温,你返回一个等长的数组,计算:**对于每一天,你还要至少等多少天才能等到一个更暖和的气温;如果等不到那一天,填 0**。
diff --git a/算法思维系列/二分查找详解.md b/算法思维系列/二分查找详解.md
index 502962f..a413541 100644
--- a/算法思维系列/二分查找详解.md
+++ b/算法思维系列/二分查找详解.md
@@ -65,7 +65,7 @@ int binarySearch(int[] nums, int target) {
### 一、寻找一个数(基本的二分搜索)
-这个场景是最简单的,肯能也是大家最熟悉的,即搜索一个数,如果存在,返回其索引,否则返回 -1。
+这个场景是最简单的,可能也是大家最熟悉的,即搜索一个数,如果存在,返回其索引,否则返回 -1。
```java
int binarySearch(int[] nums, int target) {
@@ -104,7 +104,7 @@ int binarySearch(int[] nums, int target) {
`while(left <= right)` 的终止条件是 `left == right + 1`,写成区间的形式就是 `[right + 1, right]`,或者带个具体的数字进去 `[3, 2]`,可见**这时候区间为空**,因为没有数字既大于等于 3 又小于等于 2 的吧。所以这时候 while 循环终止是正确的,直接返回 -1 即可。
-`while(left < right)` 的终止条件是 `left == right`,写成区间的形式就是 `[left, right]`,或者带个具体的数字进去 `[2, 2]`,**这时候区间非空**,还有一个数 2,但此时 while 循环终止了。也就是说这区间 `[2, 2]` 被漏掉了,索引 2 没有被搜索,如果这时候直接返回 -1 就是错误的。
+`while(left < right)` 的终止条件是 `left == right`,写成区间的形式就是 `[right, right]`,或者带个具体的数字进去 `[2, 2]`,**这时候区间非空**,还有一个数 2,但此时 while 循环终止了。也就是说这区间 `[2, 2]` 被漏掉了,索引 2 没有被搜索,如果这时候直接返回 -1 就是错误的。
当然,如果你非要用 `while(left < right)` 也可以,我们已经知道了出错的原因,就打个补丁好了:
diff --git a/算法思维系列/双指针技巧.md b/算法思维系列/双指针技巧.md
index f5edbd4..ff2aebe 100644
--- a/算法思维系列/双指针技巧.md
+++ b/算法思维系列/双指针技巧.md
@@ -20,7 +20,7 @@
[141.环形链表II](https://leetcode-cn.com/problems/linked-list-cycle-ii)
-[167.两数之和 II - 输入有序数组](https://leetcode-cn.com/problems/two-sum)
+[167.两数之和 II - 输入有序数组](https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted)
**-----------**
@@ -80,6 +80,11 @@ ListNode detectCycle(ListNode head) {
if (fast == slow) break;
}
// 上面的代码类似 hasCycle 函数
+ if (fast == null || fast.next == null) {
+ // fast 遇到空指针说明没有环
+ return null;
+ }
+
slow = head;
while (slow != fast) {
fast = fast.next;
From fb6ada33111aefc22de515579f3e680f5614b8fe Mon Sep 17 00:00:00 2001
From: labuladong
Date: Thu, 3 Dec 2020 10:43:18 +0800
Subject: [PATCH 60/63] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=87=BA=E7=89=88?=
=?UTF-8?q?=E6=8E=A8=E5=B9=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 25 ++++++++++++++++++-------
出版推广1.jpeg | Bin 0 -> 122844 bytes
2 files changed, 18 insertions(+), 7 deletions(-)
create mode 100644 出版推广1.jpeg
diff --git a/README.md b/README.md
index 45995ef..0858fff 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,8 @@ English version repo and Gitbook is on [english branch](https://github.com/labul

+好消息,《labuladong 的算法小抄》纸质书出版啦!关注公众号查看详情👆
+
@@ -27,27 +29,36 @@ English version repo and Gitbook is on [english branch](https://github.com/labul
只想要答案的话很容易,题目评论区五花八门的答案,动不动就秀 python 一行代码解决,有那么多人点赞。问题是,你去做算法题,是去学习编程语言的奇技淫巧的,还是学习算法思维的呢?你的快乐,到底源自复制别人的一行代码通过测试,已完成题目 +1,还是源自自己通过逻辑推理和算法框架不看答案写出解法?
-网上总有大佬喷我,说我写这玩意太基础了,根本没必要啰嗦。我只能说大家刷算法就是找工作吃饭的,不是打竞赛的,我也是一路摸爬滚打过来的,我们要的是清楚明白有所得,不是故弄玄虚无所指。不想办法做到通俗易懂,难道要上来先把《算法导论》吹上天,然后把人家都心怀敬仰地劝退?
+网上总有大佬喷我,说我写的东西太基础,要么说不能借助框架思维来学习算法。我只能说大家刷算法就是找工作吃饭的,不是打竞赛的,我也是一路摸爬滚打过来的,我们要的是清楚明白有所得,不是故弄玄虚无所指。
+
+不想办法做到通俗易懂,难道要上来先把《算法导论》吹上天,然后把人家都心怀敬仰地劝退?
**做啥事情做多了,都能发现套路的,我把各种算法套路框架总结出来,相信可以帮助其他人少走弯路**。我这个纯靠自学的小童鞋,花了一年时间刷题和总结,自己写了一份算法小抄,后面有目录,这里就不废话了。
### 使用方法
-1、**先给本仓库点个 star,满足一下我的虚荣心**,文章质量绝对值你一个 star。我还在继续创作,给我一点继续写文的动力,感谢。
+**1、先给本仓库点个 star,满足一下我的虚荣心**,文章质量绝对值你一个 star。我还在继续创作,给我一点继续写文的动力,感谢。
-2、**建议收藏我的 Gitbook 网站,每篇文章开头都有对应的力扣题目链接,可以边看文章边刷题**:
+**2、建议收藏我的在线网站,每篇文章开头都有对应的力扣题目链接,可以边看文章边刷题**:
-Gitbook 地址:https://labuladong.gitbook.io/algo/
+Gitbook 地址:https://labuladong.gitbook.io/algo
-3、建议关注我的公众号 **labuladong**,坚持高质量原创,说是最良心最硬核的技术公众号都不为过。本仓库的文章就是从公众号里整理出来的**一部分**内容,公众号后台回复关键词【电子书】可以获得这份小抄的完整版本;回复【加群】可以加入我们的刷题群,和大家一起讨论算法问题,分享内推机会:
+有部分读者反映 GitBook 访问速度较慢,我特意部署了两个镜像站点,大家可根据网络情况自行选择:
+
+GitHub Pages 地址:https://labuladong.github.io/algo
+
+Gitee Pages 地址:https://labuladong.gitee.io/algo
+
+
+**3、建议关注我的公众号 labuladong,坚持高质量原创,说是最良心最硬核的技术公众号都不为过**。本仓库的文章就是从公众号里整理出来的**一部分**内容,公众号可以查看更多内容;公众号后台回复关键词【加群】可以加入我们的刷题群,和大家一起讨论算法问题,分享内推机会:
-4、欢迎关注 [我的知乎](https://www.zhihu.com/people/labuladong)。
+**4、欢迎关注 [我的知乎](https://www.zhihu.com/people/labuladong)**。
-我一直在写优质文章,但是后续的文章只发布到公众号/gitbook/知乎,不能开放到 GitHub。因为本仓库太火了,很多人直接拿我的文章去开付费专栏,价格还不便宜,我这免费写给您看,何必掏冤枉钱呢?所以多多关注本作者,多多宣传,谁也不希望劣币驱逐良币不是么?
+我一直在写优质文章,但是后续的文章只发布到公众号/网站/知乎,不能开放到 GitHub。因为本仓库太火了,很多人直接拿我的文章去开付费专栏,价格还不便宜,我这免费写给您看,何必掏冤枉钱呢?所以多多关注本作者,多多宣传,谁也不希望劣币驱逐良币不是么?
其他的先不多说了,直接上干货吧,我们一起搞定 LeetCode,感受一下支配算法的乐趣。
diff --git a/出版推广1.jpeg b/出版推广1.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..6205bfee59f2363a6117d26ac667b50d06cb43cf
GIT binary patch
literal 122844
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