From 8a7b3ab51acdefb3a2a8765b053b144fb4ec7a13 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 15 Nov 2019 22:30:14 +0800 Subject: [PATCH 001/181] =?UTF-8?q?=F0=9F=90=B1(dac):=20241.=20=E4=B8=BA?= =?UTF-8?q?=E8=BF=90=E7=AE=97=E8=A1=A8=E8=BE=BE=E5=BC=8F=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E4=BC=98=E5=85=88=E7=BA=A7=20Add=20golang=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/divide-and-conquer/README.md | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/algorithm/divide-and-conquer/README.md b/docs/algorithm/divide-and-conquer/README.md index 96fd46530..388ef5982 100644 --- a/docs/algorithm/divide-and-conquer/README.md +++ b/docs/algorithm/divide-and-conquer/README.md @@ -76,6 +76,61 @@ class Solution { } ``` +#### **Go** + +```go +import ( + "fmt" + "strconv" +) + +func diffWaysToCompute(input string) []int { + // 如果是数字,直接返回 + if isDigit(input) { + tmp, _ := strconv.Atoi(input) + return []int{tmp} + } + + // 空切片 + var res []int + // 遍历字符串 + for index, c := range input { + tmpC := string(c) + fmt.Print(tmpC) + if tmpC == "+" || tmpC == "-" || tmpC == "*" { + // 如果是运算符,则计算左右两边的算式 + left := diffWaysToCompute(input[:index]) + right := diffWaysToCompute(input[index+1:]) + + for _, leftNum := range left { + for _, rightNum := range right { + var addNum int + if tmpC == "+" { + addNum = leftNum + rightNum + } else if tmpC == "-" { + addNum = leftNum - rightNum + } else { + addNum = leftNum * rightNum + } + res = append(res, addNum) + } + } + } + } + + return res +} + +// 判断是否为全数字 +func isDigit(input string) bool { + _, err := strconv.Atoi(input) + if err != nil { + return false + } + return true +} +``` + ## 395. 至少有K个重复字符的最长子串 From 488fa41cf38ca234011eec23da1ee1bb7bdd2541 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 20 Nov 2019 00:43:19 +0800 Subject: [PATCH 002/181] =?UTF-8?q?=F0=9F=90=B30027):=20Add=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++++++ answer/0027/main.go | 23 +++++++++++++++++++++++ answer/0027/main.py | 21 +++++++++++++++++++++ docs/README.md | 8 ++++++++ 4 files changed, 60 insertions(+) create mode 100644 answer/0027/main.go create mode 100644 answer/0027/main.py diff --git a/README.md b/README.md index 46fc6987a..78da35807 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,14 @@ * [双指针](algorithm/double-pointer/) * [其他](algorithm/other/) +## 题解目录 + +整理中…… + +| # | Title | Solution | Difficulty | +| ---- | ---- | ---- | ---- | +| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](), [Go]() | Easy | + ## 关于我们 ### 🐱Jalan diff --git a/answer/0027/main.go b/answer/0027/main.go new file mode 100644 index 000000000..06092e2a0 --- /dev/null +++ b/answer/0027/main.go @@ -0,0 +1,23 @@ +func removeElement(nums []int, val int) int { + length := len(nums) + if length == 0 { + return 0 + } + + i := 0 + j := 0 + for j < length { + if nums[j] == val { + // 去找一个不是 val 的值 + j++ + } else { + // 互换 + nums[i], nums[j] = nums[j], nums[i] + // i 在前进的过程中走的是 j 走过的路,一定不会再碰到 val + i++ + j++ + } + } + + return length - (j - i) +} \ No newline at end of file diff --git a/answer/0027/main.py b/answer/0027/main.py new file mode 100644 index 000000000..cdcdcb6b9 --- /dev/null +++ b/answer/0027/main.py @@ -0,0 +1,21 @@ +# python3 + +class Solution: + def removeElement(self, nums, val): + """ + :type nums: List[int] + :type val: int + :rtype: int + """ + length = len(nums) + i = 0 + j = 0 + while j < length: + if nums[j] != val: + nums[i] = nums[j] + i = i + 1 + j = j + 1 + else: + j = j + 1 + res = length - (j - i) + return res \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 46fc6987a..38ce5d2cd 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,6 +63,14 @@ * [双指针](algorithm/double-pointer/) * [其他](algorithm/other/) +## 题解目录 + +整理中…… + +| # | 标题 | 解决方法 | 思路 | 难度 | 标签 | +| ---- | ---- | ---- | ---- | ---- | ---- | +| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](), [Go]() | [思路]() | Easy | 数组/双指针 | + ## 关于我们 ### 🐱Jalan From fed9b0e4178e4b16c3bbedfa3a28bd80d1d11456 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 20 Nov 2019 00:45:43 +0800 Subject: [PATCH 003/181] =?UTF-8?q?=E2=9D=A4=EF=B8=8F(toc):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- docs/README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 78da35807..86af05ed1 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ | # | Title | Solution | Difficulty | | ---- | ---- | ---- | ---- | -| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](), [Go]() | Easy | +| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](https://github.com/JalanJiang/leetcode-notebook/blob/master/answer/0027/main.py), [Go](https://github.com/JalanJiang/leetcode-notebook/blob/master/answer/0027/main.go) | Easy | ## 关于我们 diff --git a/docs/README.md b/docs/README.md index 38ce5d2cd..86af05ed1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -67,9 +67,9 @@ 整理中…… -| # | 标题 | 解决方法 | 思路 | 难度 | 标签 | -| ---- | ---- | ---- | ---- | ---- | ---- | -| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](), [Go]() | [思路]() | Easy | 数组/双指针 | +| # | Title | Solution | Difficulty | +| ---- | ---- | ---- | ---- | +| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](https://github.com/JalanJiang/leetcode-notebook/blob/master/answer/0027/main.py), [Go](https://github.com/JalanJiang/leetcode-notebook/blob/master/answer/0027/main.go) | Easy | ## 关于我们 From 6c92a713dacbde2e5d9f60cdfa9c7f7b8a204549 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 20 Nov 2019 00:46:06 +0800 Subject: [PATCH 004/181] =?UTF-8?q?=F0=9F=92=AA(*):=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Main.java | 5 ----- index.php | 2 -- main.go | 7 ------- main.py | 6 ------ 4 files changed, 20 deletions(-) delete mode 100644 Main.java delete mode 100644 index.php delete mode 100644 main.go delete mode 100644 main.py diff --git a/Main.java b/Main.java deleted file mode 100644 index 3e2836ea8..000000000 --- a/Main.java +++ /dev/null @@ -1,5 +0,0 @@ -public class Main { - public static void main(String[] args) { - System.out.println("Hello World"); - } -} \ No newline at end of file diff --git a/index.php b/index.php deleted file mode 100644 index f7c62c01e..000000000 --- a/index.php +++ /dev/null @@ -1,2 +0,0 @@ - Date: Wed, 20 Nov 2019 00:47:57 +0800 Subject: [PATCH 005/181] =?UTF-8?q?=F0=9F=90=B1(27.=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E5=85=83=E7=B4=A0):=20Add=20golang=20code.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 36 +++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 3c3bf4f51..2819ab0d6 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -274,8 +274,10 @@ class Solution: - 同步增长双指针 - 若 `nums[j] == val` - j 变为快指针:`j = j + 1` - -### Python + + + +#### **Python** ```python # python3 @@ -301,6 +303,36 @@ class Solution: return res ``` +#### **Go** + +```go +func removeElement(nums []int, val int) int { + length := len(nums) + if length == 0 { + return 0 + } + + i := 0 + j := 0 + for j < length { + if nums[j] == val { + // 去找一个不是 val 的值 + j++ + } else { + // 互换 + nums[i], nums[j] = nums[j], nums[i] + // i 在前进的过程中走的是 j 走过的路,一定不会再碰到 val + i++ + j++ + } + } + + return length - (j - i) +} +``` + + + ## 33. 搜索旋转排序数组 From 06bc3c03ba062a967fa8ed1d78ceb3346bcd498b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 22 Nov 2019 22:43:36 +0800 Subject: [PATCH 006/181] =?UTF-8?q?=F0=9F=90=B1(double-pointer):=2027.=20?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重写题解 --- docs/data-structure/array/README.md | 94 +++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 2819ab0d6..caa15d530 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -264,16 +264,84 @@ class Solution: [原题链接](https://leetcode-cn.com/problems/remove-element/description/) -### 思路 +### 题意解读 -双指针 i, j。 +划一下题目的重点: + +- 原地移除 +- 不要使用额外的数组空间 +- 不需要考虑数组中超出新长度后面的元素 + +题目要求我们原地删除所有等于 `val` 的元素,不能使用额外空间,且**不用考虑删除后超出新数组长度后面的元素**。 + +也就是说,如果原数组 `nums` 长度为 `x`,要删除的 `val` 元素个数为 `y`,那么我们只要**把这 `n` 个要删除的元素所在位置用其他有效元素覆盖掉**,然后返回最终的数组长度 `x - y`。 + +**题目并非让我们真的删除数组的元素,而是要改写相关元素的值。** + +### 思路阐述 + +那么要如何进行元素的改写呢? + +既然要让 `val` 元素都堆在数组尾部,那么我们就派出一个开拓者探路,**只要遇到非 `val` 元素,就把它覆盖到前面来**。 + +因此,我们可以定义两个指针: + +- 快指针 `j`:用于寻找非 `val` 元素 +- 慢指针 `i`:当 `j` 找到非 `val` 元素时,就被非 `val` 元素覆盖 + +### 图解思路 + +以题中的 `nums = [3,2,2,3], val = 3` 为例。 + +开始时 `i` 和 `j` 都指向下标 0 位置: + +![初始化时,i = 0, j = 0](https://user-gold-cdn.xitu.io/2019/11/21/16e8e78d6bf1eaee?w=425&h=179&f=png&s=8968) + +此时 `j` 指向的元素为 `val`,所以把 `j` 右移动 1 位: + +![把快指针 j 右移一位](https://user-gold-cdn.xitu.io/2019/11/21/16e8e79c1dd17340?w=425&h=179&f=png&s=8969) + +此时,开拓者 `j` 找到了一个非 `val` 元素,那么就赋值给 `i` 吧: + +![赋值得到新序列](https://user-gold-cdn.xitu.io/2019/11/21/16e8e95a2b497021?w=425&h=251&f=png&s=12570) + +赋值以后,我们得到了一个新的序列 `[2, 2, 2, 3]`,我们可以得知: + +- `j` 指向的元素一定不是 `val` +- `i` 指向的元素也一定不是 `val`,因为它是从 `j` 指向的元素赋值得来的,`j` 指向非 `val` 元素才会进行赋值 + +这样一来,`i` 和 `j` 都完成了本轮使命,继续前进! + +因此每次交换以后,我们都同步增长双指针,令 `i = i + 1`,`j = j + 1`: + +![同步增长双指针](https://user-gold-cdn.xitu.io/2019/11/21/16e8e97cf4ef1990?w=425&h=225&f=png&s=9812) + +此时 `j` 又指向了一个非 `val` 元素,继续赋值: + +![再一次赋值得到新序列](https://user-gold-cdn.xitu.io/2019/11/21/16e8e989fd262a29?w=425&h=246&f=png&s=12623) + +因为本次 `i` 与 `j` 指向元素相同,所以赋值后序列没有改变。赋值操作后,我们继续同步增长双指针: + +![同步增长双指针](https://user-gold-cdn.xitu.io/2019/11/21/16e8e9a17c6ecae5?w=425&h=227&f=png&s=9909) + +此时 `j` 指向了一个 `val` 元素,无法进行赋值操作,继续增长 `j`,令 `j = j + 1`: + +![j 超出数组范围](https://user-gold-cdn.xitu.io/2019/11/21/16e8e9b72d7141a7?w=489&h=226&f=png&s=10105) + +此时我们发现 `j` 超出数组范围了,循环结束。`[2, 2, 2, 3]` 即为我们最终所求结果,而红色部分即为新数组长度,长度为 `len(nums) - (j - i)`。 + +### 总结一下 + +设置双指针 `i` 和 `j`,其中,`j` 用于寻找非 `val` 元素,来覆盖 `i` 所指向的元素。 + +- 初始时:设 `i = 0, j = 0` +- 遍历数组: + - 若 `nums[j] != val`: + - 把 `j` 的值赋给 `i`:`nums[i] = nums[j]` + - 同步增长双指针:`i = i + 1, j = j + 1` + - 若 `nums[j] == val`: + - `j` 变为快指针:`j = j + 1`,寻找下一个非 `val` 元素 -- 初始:`i = 0, j = 0` -- 若 `nums[j] != val` - - `nums[i] = nums[j]` - - 同步增长双指针 -- 若 `nums[j] == val` - - j 变为快指针:`j = j + 1` @@ -319,9 +387,8 @@ func removeElement(nums []int, val int) int { // 去找一个不是 val 的值 j++ } else { - // 互换 - nums[i], nums[j] = nums[j], nums[i] - // i 在前进的过程中走的是 j 走过的路,一定不会再碰到 val + // 赋值 + nums[i] = nums[j] i++ j++ } @@ -333,6 +400,11 @@ func removeElement(nums []int, val int) int { +### 复杂度 + +- 时间复杂度:`O(n)` +- 空间复杂度:`O(1)`,没有使用到额外空间。 + ## 33. 搜索旋转排序数组 From 491edd8745da0293222f64f97c5adbad9fc5867e Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 27 Nov 2019 18:10:48 +0800 Subject: [PATCH 007/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20538.=20=E6=8A=8A?= =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E4=B8=BA=E7=B4=AF=E5=8A=A0=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index d392cbfe5..cef6aeede 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -458,6 +458,43 @@ class Solution(object): return result ``` +## 538. 把二叉搜索树转换为累加树 + +[原题链接](https://leetcode-cn.com/problems/convert-bst-to-greater-tree/) + +### 思路 + +二叉搜索树有一个特性:它的中序遍历结果是递增序列。由此我们很容易知道,它的**反中序遍历**就是一个递减序列了。 + +题目要求「使得每个节点的值是原来的节点值加上所有大于它的节点值之和」,那么只要使用该树的反中序遍历,把先遍历到的节点值都加到当前节点上,即可得到一个「累加树」。 + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + + num = 0 + + def convertBST(self, root: TreeNode) -> TreeNode: + + # 递归 + def recursion(root: TreeNode): + if root is None: + return + recursion(root.right) + root.val += self.num + self.num = root.val + recursion(root.left) + + recursion(root) + return root +``` + ## 543. 二叉树的直径 [原题链接](https://leetcode-cn.com/problems/diameter-of-binary-tree/description/) From f345623f2135838492d636104aefc57433ecb579 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 28 Nov 2019 11:05:01 +0800 Subject: [PATCH 008/181] =?UTF-8?q?=F0=9F=90=B1(linked-list):=20237.=20?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=93=BE=E8=A1=A8=E4=B8=AD=E7=9A=84=E8=8A=82?= =?UTF-8?q?=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 83 +++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index e2f051d7a..571ccdb98 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -444,7 +444,90 @@ class Solution(object): - 设置快慢指针,当快指针走完时,慢指针刚好走到中点 - 原地将后半段反转,进行回文 +## 237. 删除链表中的节点 +[原题链接](https://leetcode-cn.com/problems/delete-node-in-a-linked-list/) + +### 思路分析 + +如果我们要在链表中删除一个节点,一般的操作是: + +1. 修改要删除节点的上一个节点的指针 +2. 将该指针指向要删除节点的下一个节点 + +例如,在链表 `[4, 5, 1, 9]` 中,当我们要删除节点 `5` 时,我们会修改节点 `5` 上一个节点 `4` 的指针,让它指向节点 `5` 的下一个节点,即节点 `1`: + +![修改节点 4 的指针,让它指向节点 1](https://pic.leetcode-cn.com/188c3905565b3609d3ce670cf1b73320908de4f6e1bdea61ab3a1b7442359def-file_1574907780588) + +**但这道题只告诉我们要删除的节点,我们并不知道该节点的上一个节点是什么**,这时候又该如何是好呢? + +既然我们要删除一个节点时需要知道它的上一个节点,如果我们无法得知上一个节点,我们就**找一个可以知道上一个节点的节点,把它变成要删除的节点,然后删除它**。 + +这样听起来好像有些拗口?没事,直接看一个例子! + +还是 `[4, 5, 1, 9]` 链表,还是删除节点 `5`。 + +首先,我们把节点 `5` 下一个节点的值赋给它,把它变成一个「不需要删除」的节点: + +![把节点 5 下一个节点的值赋给它](https://pic.leetcode-cn.com/6e65c25f7a28a7c8900fb0e8b9205b91cda81d920fb0014d606f6468a7008506-file_1574907780596) + +这样一来,第二个节点 `1` 和第三个节点 `1`,无论我们删除其中的哪一个,都可以得到最终结果 `[4, 1, 9]`。既然第二个节点不好删除,那我们就果断删除第三个啦~ + +改变第二个节点 `1` 的指针,将它指向第 4 个节点 `9`,这样一来,第三个节点 `1` 就被删除了: + +![改变第 2 个节点的指针,让它指向第 4 个节点](https://pic.leetcode-cn.com/10d4294214a45a545cecb6f072dd6b01a9e090ca67bc8d22003aed2c248a6e49-file_1574907780593) + +### 具体实现 + + + +#### **Python** + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def deleteNode(self, node): + """ + :type node: ListNode + :rtype: void Do not return anything, modify node in-place instead. + """ + node.val = node.next.val + node.next = node.next.next +``` + +#### **Go** + +```go +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +func deleteNode(node *ListNode) { + node.Val = node.Next.Val + node.Next = node.Next.Next +} +``` + + + +### 复杂度 + +- 时间复杂度 `O(1)` +- 空间复杂度 `O(1)` + +### 总结一下 + +这道题没有给出链表的头节点,而是直接给出要删除的节点,让我们进行原地删除。我们对于该节点的前一个节点一无所知,所以无法直接执行删除操作。因此,**我们将要删除节点的 `next` 节点的值赋值给要删除的节点,转而去删除 `next` 节点,从而达成目的。** + +题目中指明了「给定的节点为非末尾节点」且「链表至少包含两个节点」,所以上述方案是切实可行的。 ## 328. 奇偶链表 From b7389bf8eca46324a8a0f18a2dde224e425eea64 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 30 Nov 2019 21:31:14 +0800 Subject: [PATCH 009/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20104.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 添加详细解答链接 2. 补充 go 代码 --- docs/data-structure/tree/other/README.md | 23 ------------- docs/data-structure/tree/recursion/README.md | 35 +++++++++++++++++++- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/docs/data-structure/tree/other/README.md b/docs/data-structure/tree/other/README.md index 3a297c14d..155c740fc 100644 --- a/docs/data-structure/tree/other/README.md +++ b/docs/data-structure/tree/other/README.md @@ -63,29 +63,6 @@ class Solution: return self.checkElement(left_root.left, right_root.right) and self.checkElement(left_root.right, right_root.left) ``` -## 104. 二叉树的最大深度 - -[原题链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/description/) - -### 思路 - -递归求解~ - -取左右子树最大深度值 + 1(1 为到 root 节点的深度) - -```python -class Solution(object): - def maxDepth(self, root): - """ - :type root: TreeNode - :rtype: int - """ - if root is None: - return 0 - else: - return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1 -``` - ## 687. 最长同值路径 [原题链接](https://leetcode-cn.com/problems/longest-univalue-path/description/) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index cef6aeede..dfd6cc77c 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -38,7 +38,8 @@ class Solution: ## 104. 二叉树的最大深度 -[原题链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/description/) +- [原题链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/description/) +- [详解链接](https://juejin.im/post/5de254ce51882523467752d0) ### 思路 @@ -46,6 +47,10 @@ class Solution: 取左右子树最大深度值 + 1(1 为到 root 节点的深度) + + +#### **Python** + ```python class Solution(object): def maxDepth(self, root): @@ -59,6 +64,34 @@ class Solution(object): return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1 ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func maxDepth(root *TreeNode) int { + if root == nil { + return 0 + } + return max(maxDepth(root.Left), maxDepth(root.Right)) + 1 +} + +func max(a int, b int) int { + if a > b { + return a + } + return b +} +``` + + + ## 105. 从前序与中序遍历序列构造二叉树 From 3e05fd820d18b0c827c1b7b5519da2aad8018791 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 3 Dec 2019 21:49:34 +0800 Subject: [PATCH 010/181] =?UTF-8?q?=F0=9F=90=B1(bit):=20289.=20=E7=94=9F?= =?UTF-8?q?=E5=91=BD=E6=B8=B8=E6=88=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/bit/README.md | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/docs/algorithm/bit/README.md b/docs/algorithm/bit/README.md index 55c4282de..fc1fda219 100644 --- a/docs/algorithm/bit/README.md +++ b/docs/algorithm/bit/README.md @@ -182,6 +182,71 @@ class Solution(object): return count ``` +## 289. 生命游戏 + +[原题链接](https://leetcode-cn.com/problems/game-of-life/) + +### 思路 + +用两位二进制代表示状态: + +- 高位:下一个状态 +- 低位:现在的状态 + +因此,初始状态为 `00` 与 `01`。 + +步骤: + +1. 遍历矩阵,更新高位 +2. 再次遍历矩阵,更新最终值 + +```python +class Solution: + def gameOfLife(self, board: List[List[int]]) -> None: + """ + Do not return anything, modify board in-place instead. + """ + m = len(board) + n = len(board[0]) + # 更新矩阵 + for i in range(m): + for j in range(n): + lives = self.getLives(board, i, j) + if board[i][j] & 1 == 1: + # 活细胞 + if lives == 2 or lives == 3: + board[i][j] = 3 # 01->11 + else: + # 死细胞 + if lives == 3: + board[i][j] = 2 # 00->10 + + # 最终矩阵 + for i in range(m): + for j in range(n): + board[i][j] = board[i][j] >> 1 + + def getLives(self, board, i, j): + """ + 计算活细胞个数 + """ + m = len(board) + n = len(board[0]) + # 8 个方向 + directions = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [-1, -1], [1, -1], [-1, 1]] + + lives = 0 + + for direction in directions: + d_x = direction[0] + i + d_y = direction[1] + j + + if (d_x >= 0 and d_x < m) and (d_y >= 0 and d_y < n): + if board[d_x][d_y] & 1 == 1: + lives += 1 + + return lives +``` ## 371. 两整数之和 From 8d4b4bda4a82737c4a72e2afa8ae6317cf5efa4d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 5 Dec 2019 19:23:36 +0800 Subject: [PATCH 011/181] =?UTF-8?q?=F0=9F=90=B1(graph):=20997.=20=E6=89=BE?= =?UTF-8?q?=E5=88=B0=E5=B0=8F=E9=95=87=E7=9A=84=E6=B3=95=E5=AE=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/graph/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/data-structure/graph/README.md diff --git a/docs/data-structure/graph/README.md b/docs/data-structure/graph/README.md new file mode 100644 index 000000000..95ea26838 --- /dev/null +++ b/docs/data-structure/graph/README.md @@ -0,0 +1,28 @@ +## 997. 找到小镇的法官 + +[原题链接](https://leetcode-cn.com/problems/find-the-town-judge) + +### 思路 + +这是一道关于图的题。 + +用一个二维数组存储每个节点的入度和出度,入度 = N - 1 且 出度 = 0 的节点为法官。 + + +```python +class Solution: + def findJudge(self, N: int, trust: List[List[int]]) -> int: + node = [[0, 0] for _ in range(N + 1)] + + # 记录 + for t in trust: + node[t[0]][0] += 1 + node[t[1]][1] += 1 + + for i in range(1, N + 1): + n = node[i] + if n[1] == N - 1 and n[0] == 0: + return i + + return -1 +``` \ No newline at end of file From 7175c72a2b698458d4d053576b995c97720749d1 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 20 Dec 2019 21:51:52 +0800 Subject: [PATCH 012/181] =?UTF-8?q?=F0=9F=90=B1(binay):=20367.=20=E6=9C=89?= =?UTF-8?q?=E6=95=88=E7=9A=84=E5=AE=8C=E5=85=A8=E5=B9=B3=E6=96=B9=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 343470155..373b67f26 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -434,6 +434,87 @@ class Solution(object): return left ``` +## 367. 有效的完全平方数 + +[原题链接](https://leetcode-cn.com/problems/valid-perfect-square/) + +### 解一:暴力破解 + +#### **Python** + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + i = 1 + while i * i <= num: + if i * i == num: + return True + i += 1 + + return False +``` + +#### **Go** + +```go +func isPerfectSquare(num int) bool { + i := 1 + for i * i <= num { + if i * i == num { + return true + } + i++ + } + return false +} +``` + +### 解二:二分查找 + +#### **Python** + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + left = 1 + right = num + + while left < right: + mid = (left + right) >> 1 + tmp = mid * mid + if tmp < num: + left = mid + 1 + elif tmp > num: + right = mid - 1 + else: + return True + + return left * left == num +``` + +#### **Go** + +```go +func isPerfectSquare(num int) bool { + left := 0 + right := num + + for left < right { + mid := (left + right) >> 1 + tmp := mid * mid + if tmp < num { + left = mid + 1 + } else if tmp > num { + right = mid - 1 + } else { + return true + } + } + + return left * left == num +} +``` + ## 374. 猜数字大小 [原题链接](https://leetcode-cn.com/problems/guess-number-higher-or-lower/) From 3ec407cd519957da1ebc61f1c30d928a0bef2aa3 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 27 Dec 2019 18:08:59 +0800 Subject: [PATCH 013/181] =?UTF-8?q?=F0=9F=90=B1(array):=20807.=20=E4=BF=9D?= =?UTF-8?q?=E6=8C=81=E5=9F=8E=E5=B8=82=E5=A4=A9=E9=99=85=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 83 +++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index caa15d530..7e0cb270d 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2515,6 +2515,89 @@ class Solution: return num ``` +## 807. 保持城市天际线 + +[原题链接](https://leetcode-cn.com/problems/max-increase-to-keep-city-skyline/) + +### 思路 + +找出每一行、每一列的天际线,每个位置建筑的最大高度不能超过它所在行列的天际线。 + + + +#### **Python** + +```python +class Solution: + def maxIncreaseKeepingSkyline(self, grid: List[List[int]]) -> int: + res = 0 + m = len(grid) + n = len(grid[0]) + + top = [0 for _ in range(n)] + left = [0 for _ in range(m)] + + for i in range(m): + for j in range(n): + g = grid[i][j] + left[i] = max(left[i], g) + top[j] = max(top[j], g) + + for i in range(m): + for j in range(n): + g = grid[i][j] + res += min(left[i], top[j]) - g + + return res +``` + +#### **Go** + +```go +func maxIncreaseKeepingSkyline(grid [][]int) int { + res := 0 + m := len(grid) + n := len(grid[0]) + + left := make([]int, m) + top := make([]int, n) + + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + g := grid[i][j] + left[i] = getMax(g, left[i]) + top[j] = getMax(g, top[j]) + } + } + + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + g := grid[i][j] + res += getMin(left[i], top[j]) - g + } + } + + return res +} + +func getMax(a int, b int) int { + if a > b { + return a + } else { + return b + } +} + +func getMin(a int, b int) int { + if a < b { + return a + } else { + return b + } +} +``` + + ## 1002. 查找常用字符 From 4e832593cf679350d032d6f4a1950d17081ff5c9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 28 Dec 2019 20:28:00 +0800 Subject: [PATCH 014/181] =?UTF-8?q?=F0=9F=90=B1(math):=201276.=20=E4=B8=8D?= =?UTF-8?q?=E6=B5=AA=E8=B4=B9=E5=8E=9F=E6=96=99=E7=9A=84=E6=B1=89=E5=A0=A1?= =?UTF-8?q?=E5=88=B6=E4=BD=9C=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/math/README.md | 59 ++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/math/README.md b/docs/algorithm/math/README.md index ffb87dd27..9f18b4d0e 100644 --- a/docs/algorithm/math/README.md +++ b/docs/algorithm/math/README.md @@ -482,4 +482,61 @@ class Solution: if x_count == 0 and num != 0: return "No solution" return "x=" + str(-num // x_count) -``` \ No newline at end of file +``` + +## 1276. 不浪费原料的汉堡制作方案 + +[原题链接](https://leetcode-cn.com/problems/number-of-burgers-with-no-waste-of-ingredients/) + +### 思路 + +数学题,解方程。 + +设有 `x` 个巨无霸,`y` 个小皇堡。那么有: + +$$ +4 \times x + 2y = tomatoSlices +$$ + +$$ +x + y = cheeseSlices +$$ + +约束项: + +- `x` 与 `y` 需大于等于 0 +- `tomatoSlices` 需要是偶数 + + + +#### **Python** + +```python +class Solution: + def numOfBurgers(self, tomatoSlices: int, cheeseSlices: int) -> List[int]: + if tomatoSlices % 2 != 0 or tomatoSlices > 4 * cheeseSlices or tomatoSlices < 2 * cheeseSlices: + return [] + + y = 2 * cheeseSlices - tomatoSlices // 2 + x = cheeseSlices - y + + return [x, y] +``` + +#### **Go** + +```go +func numOfBurgers(tomatoSlices int, cheeseSlices int) []int { + if tomatoSlices % 2 != 0 || tomatoSlices > 4 * cheeseSlices || tomatoSlices < 2 * cheeseSlices { + return make([]int, 0) + } + + res := make([]int, 2) + res[1] = 2 * cheeseSlices - tomatoSlices / 2 + res[0] = cheeseSlices - res[1] + + return res +} +``` + + \ No newline at end of file From 98b5e65b4b318a44b957d14854135fb5b437f876 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 31 Dec 2019 18:23:56 +0800 Subject: [PATCH 015/181] =?UTF-8?q?=F0=9F=90=B1(recursion):=20779.=20?= =?UTF-8?q?=E7=AC=ACK=E4=B8=AA=E8=AF=AD=E6=B3=95=E7=AC=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/recursion/README.md | 53 +++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/recursion/README.md b/docs/algorithm/recursion/README.md index 846c59cdd..3009a61b0 100644 --- a/docs/algorithm/recursion/README.md +++ b/docs/algorithm/recursion/README.md @@ -51,4 +51,55 @@ class Solution: return False return dfs(0, 0, k) -``` \ No newline at end of file +``` + +## 779. 第K个语法符号 + +[原题链接](https://leetcode-cn.com/problems/k-th-symbol-in-grammar/) + +### 思路 + +通过观察规律可知:**第 N 行第 K 个数是由第 N - 1 行第 (K + 1) / 2 个数得来的**。 + +并且: + +- 当上一行的数字为 0 时,生成的数字是 `1 - (K % 2)` +- 当上一行的数字为 1 时,生成的数字是 `K % 2` + +递归函数设计: + +- 函数作用:返回第 `N` 行第 `K` 个数 +- 当 `N == 1` 时结束递归 + +#### 具体实现 + + + +#### **Python** + +```python +class Solution(object): + def kthGrammar(self, N, K): + if N == 1: + return 0 + # 得到第 N 行第 K 位的数字 + return self.kthGrammar(N - 1, (K + 1) // 2) ^ (1 - K % 2) +``` + +#### **Go** + +```go +func kthGrammar(N int, K int) int { + if N == 1 { + return 0 + } + return kthGrammar(N - 1, (K + 1) / 2) ^ (1 - K % 2) +} +``` + + + +#### 复杂度 + +- 时间复杂度:$O(N)$ +- 空间复杂度:$O(N)$ \ No newline at end of file From 1ed2a2c3ff972da768b075127c67ef385c464c3a Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 31 Dec 2019 19:45:52 +0800 Subject: [PATCH 016/181] =?UTF-8?q?=E2=9D=A4=EF=B8=8F(README):=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 86af05ed1..bd8ceb211 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,29 @@ 点击此处:[在线阅读](http://jalan.space/leetcode-notebook/) -## Rum +## 这是什么? -- 🐱 LeetCode 解题本,基于**算法与数据结构**,对做过的 LeetCode 练习题进行归纳与总结。 -- 🍸 项目代号 [Rum](https://zh.wikipedia.org/wiki/%E5%85%B0%E5%A7%86%E9%85%92)([朗姆酒](https://zh.wikipedia.org/wiki/%E5%85%B0%E5%A7%86%E9%85%92)),鸡尾酒的热带气息基酒,暗指「算法与数据结构是程序员的基底」。 -- 👩‍💻 题解主要由 Python 书写,包含少量 Java / Go / PHP / Swift 版本 -- ⚔️ 使用 [docsify](https://docsify.js.org/#/) 构建,搭建教程见 [《docsify 入坑指南与我放弃 Gitbook 的那些理由》](http://jalan.space/2019/06/21/2019/begin-docsify/) - -欢迎关注我的公众号:`CodeWarrior_`。加入编程世界一起冒险,一起成长! +LeetCode 解题本,基于**算法与数据结构**,对做过的 LeetCode 练习题进行归纳与总结。该项目代号为 [Rum](https://zh.wikipedia.org/wiki/%E5%85%B0%E5%A7%86%E9%85%92),朗姆酒是鸡尾酒的热带气息基酒,暗指「算法与数据结构是程序员的基底」。 -
+项目内题解主要由 Python 书写,包含少量 Java/Go/PHP/Swift 版本,后续会陆续补充完全。 -### 基本概念 +项目使用 [docsify](https://docsify.js.org/#/) 构建,搭建教程见 [《docsify 入坑指南与我放弃 Gitbook 的那些理由》](http://jalan.space/2019/06/21/2019/begin-docsify/) + +欢迎关注我的公众号「编程拯救世界」(CodeWarrior_),加入编程世界一起冒险,一起成长! + +![](./docs/_img/qrcode.png) + +如果你对分享题解或做题感兴趣,欢迎加入[刷题小组](https://github.com/leetcode-notebook)。 + +## 基本概念 (更新中……) - [基础算法](concept/base-algorithm/) -### 题解分类 +## 题解分类 -#### 数据结构 +### 数据结构 * [数组](data-structure/array/) * [字符串](data-structure/string/) @@ -42,7 +45,7 @@ * [栈](data-structure/stack/) * [哈希表](data-structure/hash/) -#### 算法思想 +### 算法思想 * [递归](algorithm/recursion/) * 排序 @@ -63,14 +66,6 @@ * [双指针](algorithm/double-pointer/) * [其他](algorithm/other/) -## 题解目录 - -整理中…… - -| # | Title | Solution | Difficulty | -| ---- | ---- | ---- | ---- | -| 0027 | [移除元素](https://leetcode-cn.com/problems/remove-element/) | [Python](https://github.com/JalanJiang/leetcode-notebook/blob/master/answer/0027/main.py), [Go](https://github.com/JalanJiang/leetcode-notebook/blob/master/answer/0027/main.go) | Easy | - ## 关于我们 ### 🐱Jalan From c435e5702f7ad3022f4a90ad2df2d7e08e47605d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 5 Jan 2020 20:58:12 +0800 Subject: [PATCH 017/181] =?UTF-8?q?=F0=9F=90=B1(link):=20876.=20=E9=93=BE?= =?UTF-8?q?=E8=A1=A8=E7=9A=84=E4=B8=AD=E9=97=B4=E7=BB=93=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 571ccdb98..97d33475c 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -705,5 +705,29 @@ class Solution(object): return res_list ``` +## 876. 链表的中间结点 +[原题链接](https://leetcode-cn.com/problems/middle-of-the-linked-list/solution/) +### 快慢指针 + +fast 比 slow 速度快 2 倍。这样一来,fast 到达链表尾部后,slow 正好到达中间: + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def middleNode(self, head: ListNode) -> ListNode: + slow = head + fast = head + + while fast is not None and fast.next is not None: + fast = fast.next.next + slow = slow.next + + return slow +``` \ No newline at end of file From fd9b2574112803a1485e0486471633406f976630 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 5 Jan 2020 21:09:04 +0800 Subject: [PATCH 018/181] =?UTF-8?q?=F0=9F=90=B1(link):=20141.=20=E7=8E=AF?= =?UTF-8?q?=E5=BD=A2=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 97d33475c..c69093716 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -322,6 +322,29 @@ class Solution(object): return True ``` +另一种写法: + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def hasCycle(self, head: ListNode) -> bool: + slow = head + fast = head + + while fast is not None and fast.next is not None: + fast = fast.next.next + slow = slow.next + if fast == slow: + return True + + return False +``` + ## 160. 相交链表 From c0cba75e04c12ed29068b16b044c3f347f18cb5f Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 6 Jan 2020 12:54:26 +0800 Subject: [PATCH 019/181] =?UTF-8?q?=F0=9F=90=B1(link):=2061.=20=E6=97=8B?= =?UTF-8?q?=E8=BD=AC=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index c69093716..57ebfbbfe 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -199,6 +199,62 @@ class Solution(object): return first.next ``` +## 61. 旋转链表 + +[原题链接](https://leetcode-cn.com/problems/rotate-list/solution/chuan-zhen-yin-xian-by-liweiwei1419/) + +### 思路 + +双指针 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def rotateRight(self, head: ListNode, k: int) -> ListNode: + # 倒数第 n + 1 个节点变成尾部 + # 修改导出第 n + 1 个节点的 next 指针,指向 Null + # 修改尾节点指针,指向头部 + if head is None: + return None + # 计算链表长度 + tmp = head + length = 0 + while tmp.next is not None: + length += 1 + tmp = tmp.next + tail = tmp + length += 1 + + # 计算移动位 + k %= length + # 不需要移动 + if k == 0: + return head + + i = head + j = head + + # j 先走 k 步 + for l in range(k): + j = j.next + + while j.next is not None: + j = j.next + i = i.next + + # 得到 i + i_next = i.next + tail.next = head + i.next = None + + return i_next +``` + ## 83. 删除排序链表中的重复元素 From 153f981b41c5a67ea204fcb4ca453d89c8c10e26 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 6 Jan 2020 14:45:58 +0800 Subject: [PATCH 020/181] =?UTF-8?q?=F0=9F=90=B1(link):=20206.=20=E5=8F=8D?= =?UTF-8?q?=E8=BD=AC=E9=93=BE=E8=A1=A8=20=E8=A1=A5=E5=85=85=E9=80=92?= =?UTF-8?q?=E5=BD=92=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 54 ++++++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 57ebfbbfe..518c3d83c 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -455,9 +455,9 @@ class Solution(object): ## 206. 反转链表 -[原题链接]() +[原题链接](https://leetcode-cn.com/problems/reverse-linked-list/) -### 思路 +### 迭代法 - 给一个新的链表 - 让原链表的节点与原链表断开连接 @@ -474,14 +474,64 @@ class Solution(object): newList = None #新链表 pre = None curNode = head + while curNode: tmp = curNode.next curNode.next = newList #让当前节点与原链表断开连接 newList = curNode #赋值给新链表 curNode = tmp + return newList ``` +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + if head is None: + return None + + pre = head + cur = head.next + + while cur is not None: + next_cur = cur.next + cur.next = pre + pre = cur + cur = next_cur + + head.next = None + return pre +``` + +### 递归法 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + if head is None or head.next is None: + return head + + # 取下一个节点 + node = self.reverseList(head.next) + + next_node = head.next + next_node.next = head + head.next = None + + return node +``` ## 234. 回文链表 From e6c0c42dcf3f7ea65638f0786ca04f17f16254c6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 6 Jan 2020 15:18:59 +0800 Subject: [PATCH 021/181] =?UTF-8?q?=F0=9F=90=B1(link):=2092.=20=E5=8F=8D?= =?UTF-8?q?=E8=BD=AC=E9=93=BE=E8=A1=A8=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 74 +++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 518c3d83c..697ef2fcf 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -286,6 +286,80 @@ class Solution(object): return head ``` +## 92. 反转链表 II + +[原题链接](https://leetcode-cn.com/problems/reverse-linked-list-ii/) + +### 思路 + +需要找到几个关键节点: + +1. 开始翻转的节点 `begin` +2. 开始翻转节点的前一个节点 `begin_pre` +3. 结束翻转的节点 `end` +4. 结束翻转节点的下一个节点 `end_next` + +从 `begin` 到 `end` 位置执行反转操作。此段链表翻转后需要: + +1. 修改 `begin_pre` 节点的指针,指向 `end` 节点:`begin_pre.next = end` +2. 修改 `begin` 节点的指针,指向 `end_next` 节点:`begin.next = end_next` + +注意:`m` 可能会等于 `n`。 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode: + if head is None: + return head + + if m == n: + return head + + index = 0 + pre = None + cur = head + begin_pre = None + begin = None + end = None + end_next = None + + while cur is not None: + index += 1 + next_cur = cur.next + + if index == m: + # 记录开始节点 + begin = cur + if index == m - 1: + begin_pre = cur + if index == n: + # 记录结束位置 + end = cur + if index == n + 1: + end_next = cur + + if index > m and index <= n: + # 翻转 + cur.next = pre + pre = cur + cur = next_cur + + # 修改指针位置 + begin.next = end_next + if begin_pre is None: + # 从头开始翻转了 + return end + else: + begin_pre.next = end + return head +``` + ## 138. 复制带随机指针的链表 From d2f91e8d482e3f9f7374fb87c0f4247be63613c7 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 7 Jan 2020 20:39:14 +0800 Subject: [PATCH 022/181] =?UTF-8?q?=F0=9F=90=B1(link):=20148.=20=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 697ef2fcf..84ea56636 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -475,6 +475,59 @@ class Solution: return False ``` +## 148. 排序链表 + +[原题链接](https://leetcode-cn.com/problems/sort-list/) + +### 解一:归并 + 额外空间 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def sortList(self, head: ListNode) -> ListNode: + # 只有一个节点或没有节点时,直接返回 + if head is None or head.next is None: + return head + + # 切分 + slow = head + fast = head.next + while fast is not None and fast.next is not None: + fast = fast.next.next + slow = slow.next + + r = slow.next + slow.next = None # 切断 + left = self.sortList(head) + right = self.sortList(r) + + # 合并 + h = ListNode(0) # 构造新链表 + res = h + + while left is not None and right is not None: + if left.val < right.val: + h.next = left + left = left.next + else: + h.next = right + right = right.next + h = h.next + + # 加入未排序的部分 + h.next = left if left else right + + return res.next +``` + +### 解二:归并(无需额外空间) + +@todo ## 160. 相交链表 From 2f36728a4a1fd60de715ea03694308aa416cfaf4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 7 Jan 2020 21:52:57 +0800 Subject: [PATCH 023/181] =?UTF-8?q?=F0=9F=90=B1(link):=20147.=20=E5=AF=B9?= =?UTF-8?q?=E9=93=BE=E8=A1=A8=E8=BF=9B=E8=A1=8C=E6=8F=92=E5=85=A5=E6=8E=92?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 84ea56636..58380603e 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -475,6 +475,52 @@ class Solution: return False ``` +## 147. 对链表进行插入排序 + +[原题链接](https://leetcode-cn.com/problems/insertion-sort-list/) + +### Tail 优化版 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def insertionSortList(self, head: ListNode) -> ListNode: + if head is None or head.next is None: + return head + + # 固定头部 + new_head = ListNode(float("-inf")) + + cur = head + pre = new_head + + # 加入尾部 + tail = new_head + + while cur is not None: + if tail.val < cur.val: + tail.next = cur + tail = cur + cur = cur.next + else: + cur_next = cur.next + # 此时:tail.next = cur,会产生循环,故断开 + tail.next = cur_next + while pre.next is not None and pre.next.val < cur.val: + pre = pre.next + cur.next = pre.next + pre.next = cur + cur = cur_next + pre = new_head + + return new_head.next +``` + ## 148. 排序链表 [原题链接](https://leetcode-cn.com/problems/sort-list/) From 7d057304216bfee53c89c92515894fad70a63eab Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 8 Jan 2020 10:18:48 +0800 Subject: [PATCH 024/181] =?UTF-8?q?=F0=9F=90=B1(link):=2086.=20=E5=88=86?= =?UTF-8?q?=E9=9A=94=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 58380603e..fa36709ac 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -286,6 +286,47 @@ class Solution(object): return head ``` +## 86. 分隔链表 + +[原题链接](https://leetcode-cn.com/problems/partition-list/) + +### 思路 + +创建两个链表。比 `x` 小的节点放在左链表中,比 `x` 大的节点放在右链表中,最后将两个链表连接。 + +⚠️注:记得把链表尾部置空。 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def partition(self, head: ListNode, x: int) -> ListNode: + left = ListNode(0) + right = ListNode(0) + + res = left + right_head = right + + while head is not None: + if head.val < x: + left.next = head + left = left.next + else: + right.next = head + right = right.next + head = head.next + + # 拼接链表 + left.next = right_head.next + right.next = None # 防止形成环 + + return res.next +``` + ## 92. 反转链表 II [原题链接](https://leetcode-cn.com/problems/reverse-linked-list-ii/) From d39cdab0aa23c4fdff22912ac26946ac0e052bf8 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 8 Jan 2020 11:10:00 +0800 Subject: [PATCH 025/181] =?UTF-8?q?=F0=9F=90=B1(link):=20445.=20=E4=B8=A4?= =?UTF-8?q?=E6=95=B0=E7=9B=B8=E5=8A=A0=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 55 ++++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index fa36709ac..8a578bb54 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -910,8 +910,6 @@ class Solution(object): return l1.next ``` - - ## 445. 两数相加 II ### 解法一 @@ -985,6 +983,59 @@ class Solution(object): 考虑不反转链表实现,可以用栈,Python 中就用 list `append()` 和 `pop()` 来即可。 +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: + stack1 = list() + stack2 = list() + + while l1 is not None: + stack1.append(l1.val) + l1 = l1.next + + while l2 is not None: + stack2.append(l2.val) + l2 = l2.next + + add_num = 0 + res = None + while len(stack1) > 0 or len(stack2) > 0: + num1, num2 = 0, 0 + + if len(stack1) > 0: + num1 = stack1.pop() + + if len(stack2) > 0: + num2 = stack2.pop() + + num = num1 + num2 + add_num + if num > 9: + add_num = 1 + else: + add_num = 0 + num %= 10 + + cur = ListNode(num) + cur.next = res + res = cur + + if add_num == 1: + cur = ListNode(1) + cur.next = res + res = cur + + return res +``` + +### 解法三 + +递归 ## 725. 分隔链表 From 8910bad91c45ccf184bd14a4e2f404632b5ced11 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 8 Jan 2020 17:55:53 +0800 Subject: [PATCH 026/181] =?UTF-8?q?=F0=9F=90=B1(link):=20160.=20=E7=9B=B8?= =?UTF-8?q?=E4=BA=A4=E9=93=BE=E8=A1=A8=20=E8=A1=A5=E5=85=85=E8=A7=A3?= =?UTF-8?q?=E6=B3=95=E4=BA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 39 ++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 8a578bb54..a32191832 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -620,7 +620,9 @@ class Solution: [原题链接](https://leetcode-cn.com/problems/intersection-of-two-linked-lists/description/) -### 思路 +核心思想:消除长度差。 + +### 解法一 - 找出两个链表的长度差值 step - 快慢指针,长的链表先走 step 步,然后循环两个链表 @@ -666,6 +668,41 @@ class Solution(object): return a ``` +### 解法二 + +设两个指针 `pa` 和 `pb` 分别指向 A 链表和 B 链表的表头,然后开始遍历。 + +当 `pa` 到达末尾时,将 `pa` 重置到链表 B 的头部;当 `pb` 到达尾部时,将 `pb` 重置到链表 A 的头部。用这种方法来消除 `pa` 和 `pb` 走过长度的长度差,如果 A 和 B 相交,那么 `pa` 和 `pb` 必定相遇。 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: + pa = headA + pb = headB + + while pa != pb: + # 不相交就继续走 + if pa is None: + pa = headB + else: + pa = pa.next + + if pb is None: + pb = headA + else: + pb = pb.next + + return pa +``` + +- 时间复杂度:$O(m + n)$ +- 空间复杂度:$O(1)$ ## 206. 反转链表 From 998000c070ce256cf136ca778a2e1ab2f3255bc4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 8 Jan 2020 21:25:52 +0800 Subject: [PATCH 027/181] =?UTF-8?q?=F0=9F=90=B1(link):=20143.=20=E9=87=8D?= =?UTF-8?q?=E6=8E=92=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 66 +++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 58380603e..dbe8de440 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -475,6 +475,72 @@ class Solution: return False ``` +## 143. 重排链表 + +[原题链接](https://leetcode-cn.com/problems/reorder-list/) + +### 思路 + +1. 找到链表中点 +2. 拆分链表 +3. 将拆分出的链表后半部分反转 +4. 将两个链表穿插变为一个链表 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reorderList(self, head: ListNode) -> None: + """ + Do not return anything, modify head in-place instead. + """ + if head is None or head.next is None: + return head + + i = head + j = head.next + + # 找中点 + while j is not None and j.next is not None: + j = j.next.next + i = i.next + + mid = i + right = i.next + i.next = None # 断开链表 + + # 右边链表反转 + pre = None + while right is not None: + right_next = right.next + right.next = pre + pre = right + right = right_next + + # 获取反转后的表头 + right = pre + left = head + + # 穿插操作 + while left is not None and right is not None: + left_next = left.next + right_next = right.next + + # 插入节点 + left.next = right + right.next = left_next + + left = left_next + right = right_next + + + return head +``` + ## 147. 对链表进行插入排序 [原题链接](https://leetcode-cn.com/problems/insertion-sort-list/) From 72a9723db5a0cc26405b335bb3e3758cf1bc1b54 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 11 Jan 2020 21:55:25 +0800 Subject: [PATCH 028/181] =?UTF-8?q?=F0=9F=90=B1(link):=20203.=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E9=93=BE=E8=A1=A8=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 36 +++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index dbe8de440..968d39bac 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -691,6 +691,42 @@ class Solution(object): return a ``` +## 203. 移除链表元素 + +[原题链接](https://leetcode-cn.com/problems/remove-linked-list-elements/submissions/) + +### 思路 + +同移除链表节点。 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def removeElements(self, head: ListNode, val: int) -> ListNode: + pre = None + p = head + + while p is not None: + p_next = p.next + if p.val == val: + # 移除操作 + if pre is None: + # 移除的是第一个节点 + head = p_next + else: + pre.next = p_next + p.next = None + else: + pre = p + p = p_next + + return head +``` ## 206. 反转链表 From eb7dc198c424594c118e9d88cc5d71f647e47ae3 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 15 Jan 2020 23:38:21 +0800 Subject: [PATCH 029/181] =?UTF-8?q?=F0=9F=90=B1(stack):=20173.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E8=BF=AD=E4=BB=A3=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 68 +++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index afdfe9182..ae5d6505b 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -153,6 +153,74 @@ class MinStack(object): return self.stack[len(self.stack) - 1] ``` +## 173. 二叉搜索树迭代器 + +[原题链接](https://leetcode-cn.com/problems/binary-search-tree-iterator/) + +### 解法一 + +在构造函数中使用中序遍历将二叉搜索树转为升序序列,然后在 `next` 时依次出列。 + +但时间复杂度不符合题目要求。 + +### 解法二 + +不需要一次性生成整个序列,可以用栈模拟递归过程。 + +1. 在构造函数中:将树的所有左节点压入栈(这样最左的节点就在栈顶了) +2. 调用 `next` 时,弹出栈顶元素,此时判断该节点是否存在右节点,若存在则将右节点入栈,且将该节点的所有左节点依次入栈(中序遍历的顺序为 左->中->右,弹出的栈顶元素相当于中间节点,遍历到中间节点后就要遍历右节点了) + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class BSTIterator: + + def __init__(self, root: TreeNode): + self.stack = [] + # 左节点依次入栈 + while root is not None: + self.stack.append(root) + root = root.left + + def next(self) -> int: + """ + @return the next smallest number + """ + # 弹出栈顶 + cur = self.stack.pop() + # 判断是否存在右子树 + right = cur.right + while right is not None: + self.stack.append(right) + right = right.left + return cur.val + + + def hasNext(self) -> bool: + """ + @return whether we have a next smallest number + """ + return len(self.stack) > 0 + + + +# Your BSTIterator object will be instantiated and called as such: +# obj = BSTIterator(root) +# param_1 = obj.next() +# param_2 = obj.hasNext() +``` + +关于复杂度的分析截取一下[这篇题解](https://leetcode-cn.com/problems/binary-search-tree-iterator/solution/nextshi-jian-fu-za-du-wei-o1-by-user5707f/): + +> 但是很多小伙伴会对next()中的循环操作的复杂度感到疑惑,认为既然加入了循环在里面,那时间复杂度肯定是大于O(1)不满足题目要求的。 +> 仔细分析一下,该循环只有在节点有右子树的时候才需要进行,也就是不是每一次操作都需要循环的,循环的次数加上初始化的循环总共会有O(n)次操作,均摊到每一次 `next()` 的话平均时间复杂度则是 `O(n)/n=O(1)`,因此可以确定该实现方式满足 `O(1)` 的要求。 +>这种分析方式称为摊还分析,详细的学习可以看看《算法导论》- 第17章 摊还分析 + ## 232. 用栈实现队列 [原题链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/comments/) From 603a0f75c11aeae8fc4f75eb49e8370ec13bdb54 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 24 Jan 2020 11:59:15 +0800 Subject: [PATCH 030/181] =?UTF-8?q?=F0=9F=90=B1(stack):=20331.=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E4=BA=8C=E5=8F=89=E6=A0=91=E7=9A=84=E5=89=8D=E5=BA=8F?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index ae5d6505b..d916e5bab 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -401,6 +401,44 @@ class MyStack: return True ``` +## 331. 验证二叉树的前序序列化 + +[原题链接](https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree/) + +### 解一:用栈辅助 + +按字符顺序依次入栈。如果入栈元素为 `#`,就判断栈顶能否凑成 `n##` 格式(`n` 为数字),如果可以就弹出 `n##`,让 `#` 入栈。因为 `n##` 表示一个叶节点,用 `#` 替代它以便让它的父节点达成叶节点条件(以此证明它是合法节点)。 + +```python +class Solution: + def isValidSerialization(self, preorder: str) -> bool: + + stack = list() + nodes = preorder.split(",") + + for node in nodes: + self.add_item(stack, node) + # print(stack) + + return True if len(stack) == 1 and stack[-1] == "#" else False + + def add_item(self, stack, node): + if node == "#": + if len(stack) > 1: + # 判断能否凑成 x## + if stack[-1] == "#" and stack[-2] != "#": + stack.pop() + stack.pop() + # 加入新的 # + self.add_item(stack, "#") + else: + stack.append(node) + else: + stack.append(node) + else: + stack.append(node) +``` + ## 503. 下一个更大元素 II [原题链接](https://leetcode-cn.com/problems/next-greater-element-ii/submissions/) From 0aa541d1f388e32381fa0826c3f69ad9143b98d4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 1 Feb 2020 15:33:39 +0800 Subject: [PATCH 031/181] =?UTF-8?q?=F0=9F=90=B1(recursion):=20341.=20?= =?UTF-8?q?=E6=89=81=E5=B9=B3=E5=8C=96=E5=B5=8C=E5=A5=97=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/recursion/README.md | 154 +++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/docs/algorithm/recursion/README.md b/docs/algorithm/recursion/README.md index 3009a61b0..6e0de86b9 100644 --- a/docs/algorithm/recursion/README.md +++ b/docs/algorithm/recursion/README.md @@ -1,3 +1,157 @@ +## 341. 扁平化嵌套列表迭代器 + +[原题链接](https://leetcode-cn.com/problems/flatten-nested-list-iterator/) + +### 解一:递归法 + +用一个队列辅助,设计递归函数 `generate(item)`: + +- 如果传入的 `item` 为列表,对 `item` 进行遍历,遍历出的元素再进入 `generate()` 进行递归 +- 如果传入的 `item` 不为列表(即为 `NestedInteger` 对象),调用 `item.isInteger()` 判断元素是否为整型: + - 元素为整型:直接加入辅助队列 + - 元素为列表:继续传入 `generate()` 进行递归 + +```python +# """ +# This is the interface that allows for creating nested lists. +# You should not implement it, or speculate about its implementation +# """ +#class NestedInteger: +# def isInteger(self) -> bool: +# """ +# @return True if this NestedInteger holds a single integer, rather than a nested list. +# """ +# +# def getInteger(self) -> int: +# """ +# @return the single integer that this NestedInteger holds, if it holds a single integer +# Return None if this NestedInteger holds a nested list +# """ +# +# def getList(self) -> [NestedInteger]: +# """ +# @return the nested list that this NestedInteger holds, if it holds a nested list +# Return None if this NestedInteger holds a single integer +# """ + +class NestedIterator: + def __init__(self, nestedList: [NestedInteger]): + self.data_list = [] + # 构造列表 + self.generate(nestedList) + # print(self.data_list) + + def generate(self, item): + """ + 构造列表 + """ + # 传入数据,如果是列表,进行递归 + if isinstance(item, list): + # 如果是列表,循环 + for i in item: + self.generate(i) + else: + if item.isInteger(): + # 是数字,加入队列 + self.data_list.append(item.getInteger()) + else: + # 是列表,取出列表 + self.generate(item.getList()) + + def next(self) -> int: + data = self.data_list[0] + del self.data_list[0] + return data + + def hasNext(self) -> bool: + return len(self.data_list) != 0 + +# Your NestedIterator object will be instantiated and called as such: +# i, v = NestedIterator(nestedList), [] +# while i.hasNext(): v.append(i.next()) +``` + +但该方法在构造器中一次性将列表元素全部提取,并不符合「迭代器」的概念。 + +### 解法二:栈 + +**用栈模拟递归的过程**。使用一个辅助栈,在 `hasNext()` 时不断处理栈顶的元素。使用 `flag` 标记栈顶是否已处理,并使用 `top` 记录迭代器的下一个数字。 + +一开始将整个 `nestedList` 压入栈中,每次处理栈时,都将栈顶元素取出: + +- 如果栈顶元素是列表:取出列表首个元素,将列表入栈,并将首个元素入栈 +- 如果栈顶元素不是列表: + - 如果栈顶元素是整型:将 `flag` 设置为 `True`,并将该整型赋值给 `top` + - 如果栈顶元素不是整型:使用 `getList()` 取出列表,并将列表入栈 + +当栈不为空且 `falg == False` 时,不断循环处理栈顶,直到取出下一个迭代值,将 `flag` 置为 `True`。 + +```python +# """ +# This is the interface that allows for creating nested lists. +# You should not implement it, or speculate about its implementation +# """ +#class NestedInteger: +# def isInteger(self) -> bool: +# """ +# @return True if this NestedInteger holds a single integer, rather than a nested list. +# """ +# +# def getInteger(self) -> int: +# """ +# @return the single integer that this NestedInteger holds, if it holds a single integer +# Return None if this NestedInteger holds a nested list +# """ +# +# def getList(self) -> [NestedInteger]: +# """ +# @return the nested list that this NestedInteger holds, if it holds a nested list +# Return None if this NestedInteger holds a single integer +# """ + +class NestedIterator: + def __init__(self, nestedList: [NestedInteger]): + self.stack = [] + # 初始化栈 + self.stack.append(nestedList) + self.top = 0 # 下一个元素 + self.flag = False # 栈顶是否已处理 + + def next(self) -> int: + self.flag = False # 栈顶恢复未处理状态 + return self.top + + def hasNext(self) -> bool: + if len(self.stack) == 0: + return False + + # 栈顶待处理且栈不为空 + while len(self.stack) > 0 and not self.flag: + # 取出栈顶 + top = self.stack.pop() + if isinstance(top, list): + # 如果是列表,取出首元素,并将两者都压入栈 + if len(top) > 0: + first = top[0] + del top[0] + self.stack.append(top) + self.stack.append(first) + else: + # 如果不是列表 + if top.isInteger(): + # 如果是整数,直接取出 + self.top = top.getInteger() + self.flag = True + else: + # 取出 List 压入栈 + self.stack.append(top.getList()) + return self.flag + +# Your NestedIterator object will be instantiated and called as such: +# i, v = NestedIterator(nestedList), [] +# while i.hasNext(): v.append(i.next()) +``` + ## 698. 划分为k个相等的子集 [原题链接](https://leetcode-cn.com/problems/partition-to-k-equal-sum-subsets/) From e31eb685a1c1098cbc1790b2a0e24ca5ca1f292e Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 1 Feb 2020 16:00:34 +0800 Subject: [PATCH 032/181] =?UTF-8?q?=F0=9F=90=B1(stack):=20946.=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E6=A0=88=E5=BA=8F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index d916e5bab..315685df8 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -559,4 +559,31 @@ class Solution(object): return res_list ``` +## 946. 验证栈序列 +[原题链接](https://leetcode-cn.com/problems/validate-stack-sequences/) + +模拟栈序列。 + +```python +class Solution: + def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool: + stack = [] + push_i = 0 + pop_i = 0 + length = len(pushed) + + while 1: + # 判断栈顶元素是否为 pop 元素 + if len(stack) > 0 and stack[-1] == popped[pop_i]: + stack.pop() + pop_i += 1 + else: + # 压入新的元素 + if push_i >= length: + break + stack.append(pushed[push_i]) + push_i += 1 + + return len(stack) == 0 +``` \ No newline at end of file From 7e82c2fbb5591e38f36418b99b307ec1d95041d2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 4 Feb 2020 13:05:15 +0800 Subject: [PATCH 033/181] =?UTF-8?q?=F0=9F=90=B1(queue):=20622.=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=BE=AA=E7=8E=AF=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/queue/README.md | 155 ++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/data-structure/queue/README.md diff --git a/docs/data-structure/queue/README.md b/docs/data-structure/queue/README.md new file mode 100644 index 000000000..995177108 --- /dev/null +++ b/docs/data-structure/queue/README.md @@ -0,0 +1,155 @@ +## 622. 设计循环队列 + +[原题链接](https://leetcode-cn.com/problems/design-circular-queue/) + +### 解一 + +没有过多考虑,直接用 list 实现,没有践行「循环」的概念。 + +```python +class MyCircularQueue: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the queue to be k. + """ + self.list_data = [] + self.list_length = k + + def enQueue(self, value: int) -> bool: + """ + Insert an element into the circular queue. Return true if the operation is successful. + """ + if len(self.list_data) >= self.list_length: + return False + self.list_data.append(value) + return True + + def deQueue(self) -> bool: + """ + Delete an element from the circular queue. Return true if the operation is successful. + """ + if len(self.list_data) > 0: + del(self.list_data[0]) + return True + return False + + def Front(self) -> int: + """ + Get the front item from the queue. + """ + if len(self.list_data) == 0: + return -1 + return self.list_data[0] + + def Rear(self) -> int: + """ + Get the last item from the queue. + """ + if len(self.list_data) == 0: + return -1 + return self.list_data[-1] + + def isEmpty(self) -> bool: + """ + Checks whether the circular queue is empty or not. + """ + return len(self.list_data) == 0 + + def isFull(self) -> bool: + """ + Checks whether the circular queue is full or not. + """ + return len(self.list_data) == self.list_length + + +# Your MyCircularQueue object will be instantiated and called as such: +# obj = MyCircularQueue(k) +# param_1 = obj.enQueue(value) +# param_2 = obj.deQueue() +# param_3 = obj.Front() +# param_4 = obj.Rear() +# param_5 = obj.isEmpty() +# param_6 = obj.isFull() +``` + +### 解二:循环队列 + +用数组来实现,「循环」的意思就是没有头和尾的区别。且设计数组时选择「浪费一个位置」,让数组满和空两种状态不冲突。 + +设两个指针,`front` 指向头部,`rear` 指向尾部。 + +- 当 `front == rear` 时队列为空 +- 当 `(rear + 1) % length == front` 时队列为满 + +```python +class MyCircularQueue: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the queue to be k. + """ + # 浪费一个位置 + self.k = k + 1 + # 设置双指针 + self.front = 0 + self.rear = 0 + self.list_data = [0 for _ in range(self.k)] + + def enQueue(self, value: int) -> bool: + """ + Insert an element into the circular queue. Return true if the operation is successful. + """ + if self.isFull(): + return False + self.list_data[self.rear] = value + self.rear = (self.rear + 1) % self.k + return True + + def deQueue(self) -> bool: + """ + Delete an element from the circular queue. Return true if the operation is successful. + """ + if self.isEmpty(): + return False + self.front = (self.front + 1) % self.k + return True + + def Front(self) -> int: + """ + Get the front item from the queue. + """ + if self.isEmpty(): + return -1 + return self.list_data[self.front] + + def Rear(self) -> int: + """ + Get the last item from the queue. + """ + if self.isEmpty(): + return -1 + return self.list_data[(self.rear - 1 + self.k) % self.k] + + def isEmpty(self) -> bool: + """ + Checks whether the circular queue is empty or not. + """ + return self.front == self.rear + + def isFull(self) -> bool: + """ + Checks whether the circular queue is full or not. + """ + return (self.rear + 1) % self.k == self.front + + +# Your MyCircularQueue object will be instantiated and called as such: +# obj = MyCircularQueue(k) +# param_1 = obj.enQueue(value) +# param_2 = obj.deQueue() +# param_3 = obj.Front() +# param_4 = obj.Rear() +# param_5 = obj.isEmpty() +# param_6 = obj.isFull() +``` \ No newline at end of file From 74f7ae2cb8f6432cdf3d82c7b274e9dbdd8e77d9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 4 Feb 2020 13:07:20 +0800 Subject: [PATCH 034/181] =?UTF-8?q?=F0=9F=90=B1(queue):=20933.=20=E6=9C=80?= =?UTF-8?q?=E8=BF=91=E7=9A=84=E8=AF=B7=E6=B1=82=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/queue/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/data-structure/queue/README.md b/docs/data-structure/queue/README.md index 995177108..3013580c2 100644 --- a/docs/data-structure/queue/README.md +++ b/docs/data-structure/queue/README.md @@ -152,4 +152,30 @@ class MyCircularQueue: # param_4 = obj.Rear() # param_5 = obj.isEmpty() # param_6 = obj.isFull() +``` + +## 933. 最近的请求次数 + +[原题链接](https://leetcode-cn.com/problems/number-of-recent-calls/) + +### 思路 + +```python +class RecentCounter: + + def __init__(self): + self.ping_list = [] + + def ping(self, t: int) -> int: + first = t - 3000 + self.ping_list.append(t) + while first > self.ping_list[0]: + del(self.ping_list[0]) + + return len(self.ping_list) + + +# Your RecentCounter object will be instantiated and called as such: +# obj = RecentCounter() +# param_1 = obj.ping(t) ``` \ No newline at end of file From 234526c6cd8b351ab9940c6c5fec29ba09db524b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 4 Feb 2020 13:18:06 +0800 Subject: [PATCH 035/181] =?UTF-8?q?=F0=9F=90=B1(queue):=20641.=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=BE=AA=E7=8E=AF=E5=8F=8C=E7=AB=AF=E9=98=9F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/queue/README.md | 99 +++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/docs/data-structure/queue/README.md b/docs/data-structure/queue/README.md index 3013580c2..169ef9ed5 100644 --- a/docs/data-structure/queue/README.md +++ b/docs/data-structure/queue/README.md @@ -154,6 +154,105 @@ class MyCircularQueue: # param_6 = obj.isFull() ``` +## 641. 设计循环双端队列 + +[原题链接](https://leetcode-cn.com/problems/design-circular-deque/) + +### 思路 + +同上题(622. 设计循环队列)。 + +```python +class MyCircularDeque: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.k = k + 1 + self.front = 0 + self.rear = 0 + self.list_data = [0 for _ in range(self.k)] + + def insertFront(self, value: int) -> bool: + """ + Adds an item at the front of Deque. Return true if the operation is successful. + """ + if self.isFull(): + return False + self.front = (self.front - 1) % self.k + self.list_data[self.front] = value + return True + + def insertLast(self, value: int) -> bool: + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + """ + if self.isFull(): + return False + self.list_data[self.rear] = value + self.rear = (self.rear + 1) % self.k + return True + + def deleteFront(self) -> bool: + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + """ + if self.isEmpty(): + return False + self.front = (self.front + 1) % self.k + return True + + def deleteLast(self) -> bool: + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + """ + if self.isEmpty(): + return False + self.rear = (self.rear - 1) % self.k + return True + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + if self.isEmpty(): + return -1 + return self.list_data[self.front] + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + if self.isEmpty(): + return -1 + return self.list_data[(self.rear - 1 + self.k) % self.k] + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return self.front == self.rear + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return (self.rear + 1) % self.k == self.front + + +# Your MyCircularDeque object will be instantiated and called as such: +# obj = MyCircularDeque(k) +# param_1 = obj.insertFront(value) +# param_2 = obj.insertLast(value) +# param_3 = obj.deleteFront() +# param_4 = obj.deleteLast() +# param_5 = obj.getFront() +# param_6 = obj.getRear() +# param_7 = obj.isEmpty() +# param_8 = obj.isFull() +``` + ## 933. 最近的请求次数 [原题链接](https://leetcode-cn.com/problems/number-of-recent-calls/) From bcc7528894494d9e46c7be4257d7546bbea10288 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 5 Feb 2020 12:46:20 +0800 Subject: [PATCH 036/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20705.=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=93=88=E5=B8=8C=E9=9B=86=E5=90=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 52ee3309e..a422bbe96 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -440,4 +440,52 @@ class Solution(object): return max_length ``` +## 705. 设计哈希集合 +[原题链接](https://leetcode-cn.com/problems/design-hashset/) + +### 思路 + +此题应当要用普通的数据结构实现哈希集合。 + +题目指出「所有的值都在 `[0, 1000000]` 的范围内」,因此我们可以设计 100 个桶,每个桶内容纳 10000 个值,正好可以容纳下所有的数据。 + +哈希函数的映射规则:`hash_table[key % bucket][key // bucket]` + +```python +class MyHashSet: + def __init__(self): + """ + Initialize your data structure here. + """ + # 给出 100 个桶 + self.bucket = 100 + # 桶内元素 + self.bucket_num = 10000 + # 初始化 + self.hash_table = [[] for _ in range(self.bucket)] + + def add(self, key: int) -> None: + if not self.hash_table[key % self.bucket]: + self.hash_table[key % self.bucket] = [0] * self.bucket_num + self.hash_table[key % self.bucket][key // self.bucket] = 1 + + def remove(self, key: int) -> None: + if self.hash_table[key % self.bucket]: + self.hash_table[key % self.bucket][key // self.bucket] = 0 + + def contains(self, key: int) -> bool: + """ + Returns true if this set contains the specified element + """ + if not self.hash_table[key % self.bucket]: + return False + return self.hash_table[key%self.bucket][key//self.bucket] == 1 + + +# Your MyHashSet object will be instantiated and called as such: +# obj = MyHashSet() +# obj.add(key) +# obj.remove(key) +# param_3 = obj.contains(key) +``` \ No newline at end of file From d1de50f57872ebcbe002a6f0e40a1059b5dd974e Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 5 Feb 2020 12:50:08 +0800 Subject: [PATCH 037/181] =?UTF-8?q?=F0=9F=A4=94(hash):=20705.=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=93=88=E5=B8=8C=E9=9B=86=E5=90=88=20=E5=BE=85?= =?UTF-8?q?=E5=A1=AB=E5=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index a422bbe96..7b57c7c4c 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -444,7 +444,7 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/design-hashset/) -### 思路 +### 解一:数组模拟 此题应当要用普通的数据结构实现哈希集合。 @@ -488,4 +488,6 @@ class MyHashSet: # obj.add(key) # obj.remove(key) # param_3 = obj.contains(key) -``` \ No newline at end of file +``` + +### 解二:链表模拟 \ No newline at end of file From 405e39710e60e61811669d0a55a5e7d7b67fec16 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 10 Feb 2020 10:44:56 +0800 Subject: [PATCH 038/181] =?UTF-8?q?=F0=9F=90=B1(list):=20752.=20=E6=89=93?= =?UTF-8?q?=E5=BC=80=E8=BD=AC=E7=9B=98=E9=94=81=EF=BC=88=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E4=B8=8E=E5=B9=BF=E5=BA=A6=E4=BC=98=E5=85=88=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/queue/README.md | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/data-structure/queue/README.md b/docs/data-structure/queue/README.md index 169ef9ed5..cfa4eaa50 100644 --- a/docs/data-structure/queue/README.md +++ b/docs/data-structure/queue/README.md @@ -253,6 +253,52 @@ class MyCircularDeque: # param_8 = obj.isFull() ``` +## 752. 打开转盘锁 + +[原题链接](https://leetcode-cn.com/problems/open-the-lock/) + +### 思路 + +BFS + +```python +class Solution: + def openLock(self, deadends: List[str], target: str) -> int: + queue = list() + queue.append(('0000', 0)) # 0000 也有可能是死亡数字 + already = {'0000'} # 节点是否已经遍历过 + while len(queue): # 当队列不为空时,循环队列 + # 取第一个元素 + node = queue[0] + del queue[0] + # 节点判断 + if node[0] == target: + return node[1] + if node[0] in deadends: + continue + # 获取周边节点 + negihbors = self.get_neighbors(node) + for n in negihbors: + if n[0] not in already: + already.add(n[0]) + queue.append(n) + return -1 + + def get_neighbors(self, node): + number = node[0] + # print(number) + depth = node[1] + negihbors = [] + directions = {1, -1} + for i in range(len(number)): + # 循环位 + for d in directions: + new_position = str((int(number[i]) + d) % 10) + item = (number[:i] + new_position + number[i+1:], depth + 1) + negihbors.append(item) + return negihbors +``` + ## 933. 最近的请求次数 [原题链接](https://leetcode-cn.com/problems/number-of-recent-calls/) From 3010dc09f2c06e4fca8bce8a2182e0d44cb48cb2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 11 Feb 2020 20:08:10 +0800 Subject: [PATCH 039/181] =?UTF-8?q?=F0=9F=90=B1(graph):=20133.=20=E5=85=8B?= =?UTF-8?q?=E9=9A=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/graph/README.md | 79 +++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/docs/data-structure/graph/README.md b/docs/data-structure/graph/README.md index 95ea26838..3f26eca49 100644 --- a/docs/data-structure/graph/README.md +++ b/docs/data-structure/graph/README.md @@ -1,3 +1,82 @@ +## 133. 克隆图 + +[原题链接](https://leetcode-cn.com/problems/clone-graph/) + +### DFS + +用字典 `mark` 记录遍历过的节点,`mark[node] = clone` 用于对应 `node` 的拷贝节点 `clone`。 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = []): + self.val = val + self.neighbors = neighbors +""" +class Solution: + def cloneGraph(self, node: 'Node') -> 'Node': + # 记录访问过的节点 + mark = dict() + + def dfs(node): + if node is None: + return node + if node in mark: + return mark[node] + + clone = Node(node.val, []) + mark[node] = clone # node 对应的克隆节点为 clone,记录在字典中 + for n in node.neighbors: + clone.neighbors.append(dfs(n)) + + # 返回克隆节点 + return clone + + return dfs(node) +``` + +### BFS + +用辅助队列实现 BFS。 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = []): + self.val = val + self.neighbors = neighbors +""" +class Solution: + def cloneGraph(self, node: 'Node') -> 'Node': + if node is None: + return node + + # 记录 node 对应的拷贝 + mark = dict() + # 辅助队列 + queue = list() + queue.append(node) + clone = Node(node.val, []) + + mark[node] = clone + + while len(queue) > 0: + # 取出一个节点 + node = queue[0] + del queue[0] + # 遍历邻接节点 + for n in node.neighbors: + if n not in mark: + mark[n] = Node(n.val, []) + # 新节点入队列 + queue.append(n) + mark[node].neighbors.append(mark[n]) + + return clone +``` + ## 997. 找到小镇的法官 [原题链接](https://leetcode-cn.com/problems/find-the-town-judge) From b26573f914145bc1d468a540a029f93606c87c5b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 13 Feb 2020 12:23:44 +0800 Subject: [PATCH 040/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E5=89=91=E6=8C=87=20offer=20=E7=B3=BB=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 面试题06. 从尾到头打印链表 --- docs/_sidebar.md | 3 +- docs/offer/README.md | 124 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 docs/offer/README.md diff --git a/docs/_sidebar.md b/docs/_sidebar.md index dfa6796e3..dec7b12a5 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -40,4 +40,5 @@ * 3.3 竞赛 * [周赛](weekly/) * [双周赛](biweekly/) - * [其他](other/) \ No newline at end of file + * [其他](other/) + * [3.4 剑指 offer 系列](offer/) \ No newline at end of file diff --git a/docs/offer/README.md b/docs/offer/README.md new file mode 100644 index 000000000..dce024d06 --- /dev/null +++ b/docs/offer/README.md @@ -0,0 +1,124 @@ +## 面试题06. 从尾到头打印链表 + +[原题链接](https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/) + +输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 + +**示例 1:** + +``` +输入:head = [1,3,2] +输出:[2,3,1] +``` + +限制: + +`0 <= 链表长度 <= 10000` + +### 解一:栈 + +根据「从尾到头反过来」的描述很容易想到有着「先进后出」特征的数据结构 —— **栈**。 + +我们可以利用栈完成这一逆序过程,将链表节点值按顺序逐个压入栈中,再按各个节点值的弹出顺序返回即可。 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reversePrint(self, head: ListNode) -> List[int]: + stack = list() + while head is not None: + stack.append(head.val) + head = head.next + + return stack[::-1] +``` + +复杂度: + +- 时间复杂度:$O(n)$ +- 空间复杂度:$O(n)$ + +### 解二:递归 + +递归也能模拟栈的逆序过程。 + +我们将链表节点传入递归函数,递归函数设计如下: + +- 递归函数作用:将链表节点值逆序存入结果集 +- 结束条件:当节点为空时 +- 递归调用条件:当下一个节点不为空时 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reversePrint(self, head: ListNode) -> List[int]: + res = [] + self.reverse(head, res) + return res + + def reverse(self, head, res): + if head is None: + return + if head.next is not None: + # 下一个节点不为空:递归调用 + self.reverse(head.next, res) + res.append(head.val) +``` + +简化一下: + + + +#### **Python** + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reversePrint(self, head: ListNode) -> List[int]: + if head is None: + return [] + res = self.reversePrint(head.next) + res.append(head.val) + return res +``` + +#### **Go** + +```go +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +func reversePrint(head *ListNode) []int { + if head == nil { + return []int{} + } + res := reversePrint(head.Next) + return append(res, head.Val) +} +``` + + + +复杂度: + +- 时间复杂度:$O(n)$ +- 空间复杂度:$O(n)$ \ No newline at end of file From 165899ca78c3e65bfaa283d763d95bdca5231dcb Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 14 Feb 2020 00:12:02 +0800 Subject: [PATCH 041/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=9803.=20=E6=95=B0=E7=BB=84=E4=B8=AD=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84=E6=95=B0=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index dce024d06..46dbd9f35 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -1,3 +1,58 @@ +## 面试题03. 数组中重复的数字 + +[原题链接](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/) + +找出数组中重复的数字。 + + +在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。 + +示例 1: + +``` +输入: +[2, 3, 1, 0, 2, 5, 3] +输出:2 或 3 +``` + +限制: + +`2 <= n <= 100000` + +### 哈希 + + + +#### **Python** + +```python +class Solution: + def findRepeatNumber(self, nums: List[int]) -> int: + m = dict() + for n in nums: + if n in m: + return n + m[n] = True +``` + +#### **Go** + +```go +func findRepeatNumber(nums []int) int { + m := make([]int, len(nums)) + for _, e := range nums { + if m[e] == 1 { + return e + } + m[e] = 1 + } + return -1 +} +``` + + + + ## 面试题06. 从尾到头打印链表 [原题链接](https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/) From 4837e80f4918d78e05a6f39daed37aa8432c2d56 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 15 Feb 2020 16:31:03 +0800 Subject: [PATCH 042/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20494.=20?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E5=92=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 130 +++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 70c3c2727..9a093f3d6 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1027,6 +1027,136 @@ class Solution(object): return cash ``` +## 494. 目标和 + +[原题链接](https://leetcode-cn.com/problems/target-sum/) + +### 解一:递归遍历所有情况 + +**本方法超出时间限制**。 + + + +#### **Python** + +```python +class Solution: + + res = 0 + + def findTargetSumWays(self, nums: List[int], S: int) -> int: + length = len(nums) + + def helper(index, cur): + if index == length: + print('res' + str(cur)) + if cur == S: + self.res += 1 + pass + return + for op in ["+", "-"]: + helper(index + 1, eval(str(cur) + op + str(nums[index]))) + + # 或直接调用两次递归: + # helper(index + 1, cur + nums[index]) + # helper(index + 1, cur - nums[index]) + + helper(0, 0) + return self.res +``` + +#### **Go** + +```go +var count int = 0 + +func findTargetSumWays(nums []int, S int) int { + helper(nums, 0, 0, S) + return count +} + +func helper(nums []int, cur int, index int, S int) { + if index == len(nums) { + if cur == S { + count += 1 + } + return + } + helper(nums, cur + nums[index], index + 1, S) + helper(nums, cur - nums[index], index + 1, S) +} +``` + + + +- 时间复杂度:$O(2^n)$ +- 空间复杂度:$O(n)$(递归调用栈) + +### 解二:动态规划 + +`dp[i][j]` 带表前 `i` 个数可得到和为 `j` 的组合数量。那么有推导式: + +``` +dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]] +``` + +也可写作: + +``` +dp[i][j + nums[i]] += dp[i - 1][j] +dp[i][j - nums[i]] += dp[i - 1][j] +``` + + + +#### **Python** + +```python +class Solution: + def findTargetSumWays(self, nums: List[int], S: int) -> int: + # 初始化 + length = len(nums) + dp = [[0 for _ in range(2001)] for _ in range(length)] + dp[0][nums[0] + 1000] = 1 + dp[0][-nums[0] + 1000] += 1 + + for i in range(1, length): + for s in range(-1000, 1001): + if dp[i - 1][s + 1000] > 0: + # 防止越界 + dp[i][s + nums[i] + 1000] += dp[i - 1][s + 1000] + dp[i][s - nums[i] + 1000] += dp[i - 1][s + 1000] + + return 0 if S > 1000 else dp[length - 1][S + 1000] +``` + +#### **Go** + +```go +func findTargetSumWays(nums []int, S int) int { + length := len(nums) + var dp [21][2001]int + dp[0][nums[0] + 1000] = 1 + dp[0][-nums[0] + 1000] += 1 + for i := 1; i < length; i++ { + for j := -1000; j < 1001; j++ { + if dp[i - 1][j + 1000] > 0 { + dp[i][j + nums[i] + 1000] += dp[i - 1][j + 1000] + dp[i][j - nums[i] + 1000] += dp[i - 1][j + 1000] + } + } + } + if S > 1000 { + return 0 + } + return dp[length - 1][S + 1000] +} +``` + + + +### 【TODO】解三:01 背包 + ## 740. 删除与获得点数 [原题链接](https://leetcode-cn.com/problems/delete-and-earn/) From f5bf9344dbd0aec618c3af6c13a0436cec5fe0b2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 15 Feb 2020 21:02:24 +0800 Subject: [PATCH 043/181] =?UTF-8?q?=F0=9F=A4=93(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=9824.=20=E5=8F=8D=E8=BD=AC=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 48 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/offer/README.md b/docs/offer/README.md index 46dbd9f35..5703c1d82 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -176,4 +176,50 @@ func reversePrint(head *ListNode) []int { 复杂度: - 时间复杂度:$O(n)$ -- 空间复杂度:$O(n)$ \ No newline at end of file +- 空间复杂度:$O(n)$ + +## 面试题24. 反转链表 + +[原题链接](https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/) + +### 解一 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + pre = None + while head: + next_node = head.next + head.next = pre + pre = head + head = next_node + return pre +``` + +### 解二:递归法 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseList(self, head: ListNode) -> ListNode: + if head is None or head.next is None: + return head + # 自顶向下,把 head 的后面的头传进去翻转,得到的是翻转链表的尾巴,后面链表翻转完的尾巴就是 head.next + cur = self.reverseList(head.next) + # 翻转最后一个 head。由于链表翻转完的尾巴就是 head.next,要让 head 变为最后一个,那就是 head.next.next = head + head.next.next = head + # 断开链接 + head.next = None + return cur +``` \ No newline at end of file From 884ca6c629216d524ddc46e3f30fcc2dca5973a6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 23 Feb 2020 20:11:08 +0800 Subject: [PATCH 044/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20144.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=89=8D=E5=BA=8F=E9=81=8D=E5=8E=86?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=E5=BE=AA=E7=8E=AF=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/dfs/README.md | 5 ++++- docs/offer/README.md | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/tree/dfs/README.md b/docs/data-structure/tree/dfs/README.md index aea369b40..749f0daaa 100644 --- a/docs/data-structure/tree/dfs/README.md +++ b/docs/data-structure/tree/dfs/README.md @@ -185,7 +185,10 @@ class Solution(object): ### 解法二 -非递归,使用 list 模拟栈。 +非递归,使用栈辅助。 + +- 将 root 右节点、左节点依次压入栈 +- 循环弹出栈顶节点,再按节点的右、左节点依次入栈 ```python class Solution(object): diff --git a/docs/offer/README.md b/docs/offer/README.md index 5703c1d82..aa6f05feb 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -52,7 +52,6 @@ func findRepeatNumber(nums []int) int { - ## 面试题06. 从尾到头打印链表 [原题链接](https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/) From 459f7a611b32de9dc696a74540ef6495e31d2498 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 24 Feb 2020 22:32:48 +0800 Subject: [PATCH 045/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=20golang=20=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/dfs/README.md | 75 ++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/docs/data-structure/tree/dfs/README.md b/docs/data-structure/tree/dfs/README.md index 749f0daaa..cd6b0a507 100644 --- a/docs/data-structure/tree/dfs/README.md +++ b/docs/data-structure/tree/dfs/README.md @@ -14,6 +14,10 @@ void dfs(TreeNode root) { } ``` + + +#### **Python** + ```python class Solution(object): def inorderTraversal(self, root): @@ -33,12 +37,47 @@ class Solution(object): self.visitNode(root.right, l) ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +var res []int + +func inorderTraversal(root *TreeNode) []int { + res = make([]int, 0) + handler(root) + return res +} + +func handler(root *TreeNode) { + if root == nil { + return + } + handler(root.Left) + res = append(res, root.Val) + handler(root.Right) +} +``` + + + ### 解法二 非递归法。 - 寻找当前节点的左节点,依次入栈 +#### **Python** + + + ```python class Solution(object): def inorderTraversal(self, root): @@ -55,10 +94,46 @@ class Solution(object): cur = cur.left node = stack.pop() res.append(node.val) + # 下一个节点轮到右节点(左 -> 中 -> 右) cur = node.right return res ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +func inorderTraversal(root *TreeNode) []int { + if root == nil { + return nil + } + stack := make([]*TreeNode, 0) + res := make([]int, 0) + for root != nil || len(stack) > 0 { + for root != nil { + stack = append(stack, root) + root = root.Left + } + // 取栈顶 + top := stack[len(stack) - 1] + res = append(res, top.Val) + // 删除栈顶 + stack = stack[:len(stack) - 1] + root = top.Right + } + return res +} +``` + + ## 98. 验证二叉搜索树 From 76bd6cf4c38648f3b2781244e027be2105db15db Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 25 Feb 2020 20:41:26 +0800 Subject: [PATCH 046/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20145.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=90=8E=E5=BA=8F=E9=81=8D=E5=8E=86?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=20go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/dfs/README.md | 154 +++++++++++++++++++------ 1 file changed, 117 insertions(+), 37 deletions(-) diff --git a/docs/data-structure/tree/dfs/README.md b/docs/data-structure/tree/dfs/README.md index cd6b0a507..a136a5917 100644 --- a/docs/data-structure/tree/dfs/README.md +++ b/docs/data-structure/tree/dfs/README.md @@ -291,65 +291,145 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/binary-tree-postorder-traversal/) -### 解法一 +### 解法一:递归 -- 递归 +后序遍历。 -后序遍历: + -``` -void dfs(TreeNode root) { - dfs(root.left); - dfs(root.right); - visit(root); -} -``` +#### **Python** ```python -class Solution(object): - def postorderTraversal(self, root): - """ - :type root: TreeNode - :rtype: List[int] - """ - l = [] - self.visitRoot(root, l) - return l - - def visitRoot(self, root, l): +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + res = [] + self.handler(root, res) + return res + + def handler(self, root, res): if root is None: return - self.visitRoot(root.left, l) - self.visitRoot(root.right, l) - l.append(root.val) + self.handler(root.left, res) + self.handler(root.right, res) + res.append(root.val) ``` -### 解法二 +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +var res []int + +func postorderTraversal(root *TreeNode) []int { + res = make([]int, 0) + handler(root) + return res +} + +func handler(root *TreeNode) { + if root == nil { + return + } + handler(root.Left) + handler(root.Right) + res = append(res, root.Val) +} +``` + + + +### 解法二:迭代 - 后序遍历顺序为 left->right->root,反序后为:root->right->left - 用栈实现 root->right->left 的顺序,再将列表反序 + + +#### **Python** + ```python -class Solution(object): - def postorderTraversal(self, root): - """ - :type root: TreeNode - :rtype: List[int] - """ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def postorderTraversal(self, root: TreeNode) -> List[int]: + # 后序遍历:左 -> 右 -> 中 + # 反过来:中 -> 右 -> 左 stack = [] stack.append(root) res = [] - while stack: - node = stack.pop() - if node is None: + while len(stack) > 0: + top = stack.pop() + if top is None: continue - stack.append(node.left) - stack.append(node.right) - res.append(node.val) + # 用栈先将左节点入栈 + stack.append(top.left) + stack.append(top.right) + res.append(top.val) res.reverse() return res ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +var res []int + +func postorderTraversal(root *TreeNode) []int { + res := make([]int, 0) + stack := make([]*TreeNode, 0) + stack = append(stack, root) + for len(stack) > 0 { + top := stack[len(stack) - 1] + // 删除栈顶 + stack = stack[:len(stack) - 1] + if top == nil { + continue + } + stack = append(stack, top.Left) + stack = append(stack, top.Right) + res = append(res, top.Val) + } + res = reverse(res) + return res +} + +func reverse(res []int) []int { + for i, j := 0, len(res) - 1; i < j; i, j = i + 1, j - 1 { + res[i], res[j] = res[j], res[i] + } + return res +} +``` + + + ## 230. 二叉搜索树中第K小的元素 [原题链接](https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/) From f1759c64ac92e8187f1edc26563f7d456f583f97 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 26 Feb 2020 20:14:14 +0800 Subject: [PATCH 047/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20102.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=B1=82=E6=AC=A1=E9=81=8D=E5=8E=86?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=20golang=20=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/bfs/README.md | 86 ++++++++++++++++++-------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/docs/data-structure/tree/bfs/README.md b/docs/data-structure/tree/bfs/README.md index 2f554973f..e278097a1 100644 --- a/docs/data-structure/tree/bfs/README.md +++ b/docs/data-structure/tree/bfs/README.md @@ -11,43 +11,77 @@ - 若该节点的左节点不为空:左节点入队列 - 若该节点的右节点不为空:右节点入队列 + + +#### **Python** + ```python # Definition for a binary tree node. -# class TreeNode(object): +# class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None -class Solution(object): - def levelOrder(self, root): - """ - :type root: TreeNode - :rtype: List[List[int]] - """ - if root is None: - return [] - - q = list() - res = list() - q.append(root) - while q: - tmp = list() - # 此时队列中的节点为同层节点 - for i in range(len(q)): - node = q[0] - del q[0] - #if node is not None: +class Solution: + def levelOrder(self, root: TreeNode) -> List[List[int]]: + queue = [] + queue.append(root) + res = [] + while len(queue) > 0: + length = len(queue) + tmp = [] + for i in range(length): + node = queue[0] + del queue[0] + if node is None: + continue tmp.append(node.val) - if node.left is not None: - q.append(node.left) - if node.right is not None: - q.append(node.right) - - res.append(tmp) + queue.append(node.left) + queue.append(node.right) + if len(tmp) > 0: + res.append(tmp) return res ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func levelOrder(root *TreeNode) [][]int { + queue := make([]*TreeNode, 0) + queue = append(queue, root) + res := make([][]int, 0) + for len(queue) > 0 { + tmp := make([]int, 0) + length := len(queue) + for i := 0; i < length; i++ { + q := queue[0] + queue = queue[1:] + if q == nil { + continue + } + tmp = append(tmp, q.Val) + queue = append(queue, q.Left) + queue = append(queue, q.Right) + } + if len(tmp) > 0 { + res = append(res, tmp) + } + } + return res +} +``` + + + ## 108. 将有序数组转换为二叉搜索树 [原题链接](https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/submissions/) From 2775eba5fdbf6920383bc90b7750a85078b321b8 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 27 Feb 2020 22:10:40 +0800 Subject: [PATCH 048/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20104.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 66 +++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index dfd6cc77c..b8ec6dd62 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -41,9 +41,71 @@ class Solution: - [原题链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/description/) - [详解链接](https://juejin.im/post/5de254ce51882523467752d0) -### 思路 +### 自顶向下 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + depth = 0 + def maxDepth(self, root: TreeNode) -> int: + self.depth = 0 + self.handler(root, 1) + return self.depth + + def handler(self, root, depth): + if root is None: + return + self.depth = max(self.depth, depth) + self.handler(root.left, depth + 1) + self.handler(root.right, depth + 1) +``` + +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +var depth int +func maxDepth(root *TreeNode) int { + depth = 0 + handler(root, 1) + return depth +} + +func handler(root *TreeNode, curDepth int) { + if root == nil { + return + } + if curDepth > depth { + depth = curDepth + } + handler(root.Left, curDepth + 1) + handler(root.Right, curDepth + 1) +} +``` + + + +### 自底向上 -递归求解~ +「自底向上」:我们首先对所有子节点递归地调用函数,然后根据返回值和根节点本身的值得到答案。 取左右子树最大深度值 + 1(1 为到 root 节点的深度) From dc3cc0ae11252f359c3c3c0a893c9f4507ad378f Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 28 Feb 2020 23:51:40 +0800 Subject: [PATCH 049/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20101.=20=E5=AF=B9?= =?UTF-8?q?=E7=A7=B0=E4=BA=8C=E5=8F=89=E6=A0=91=20=E8=A1=A5=E5=85=85=20gol?= =?UTF-8?q?ang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/other/README.md | 37 ++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/tree/other/README.md b/docs/data-structure/tree/other/README.md index 155c740fc..ddbf2c840 100644 --- a/docs/data-structure/tree/other/README.md +++ b/docs/data-structure/tree/other/README.md @@ -2,7 +2,7 @@ [原题链接](https://leetcode-cn.com/problems/symmetric-tree/description/) -### 思路 +### 解一:递归 递归法,判断二叉树是否为镜像对称。 @@ -34,7 +34,9 @@ else: - A节点的左节点与B节点的右节点 - A节点的右节点与B节点的左节点 -### python 实现 + + +#### **Python** ```python # Definition for a binary tree node. @@ -63,6 +65,37 @@ class Solution: return self.checkElement(left_root.left, right_root.right) and self.checkElement(left_root.right, right_root.left) ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func isSymmetric(root *TreeNode) bool { + if root == nil { + return true + } + return symmetric(root.Left, root.Right) +} + +func symmetric(left *TreeNode, right *TreeNode) bool { + if left == nil || right == nil { + return left == right + } + if left.Val != right.Val { + return false + } + return symmetric(left.Left, right.Right) && symmetric(left.Right, right.Left) +} +``` + + + ## 687. 最长同值路径 [原题链接](https://leetcode-cn.com/problems/longest-univalue-path/description/) From e089b7ad64247c709a761739c8bf4ea011f55d2e Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 29 Feb 2020 00:38:17 +0800 Subject: [PATCH 050/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20101.=20=E5=AF=B9?= =?UTF-8?q?=E7=A7=B0=E4=BA=8C=E5=8F=89=E6=A0=91=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/other/README.md | 94 ++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/data-structure/tree/other/README.md b/docs/data-structure/tree/other/README.md index ddbf2c840..8378eaff8 100644 --- a/docs/data-structure/tree/other/README.md +++ b/docs/data-structure/tree/other/README.md @@ -96,6 +96,100 @@ func symmetric(left *TreeNode, right *TreeNode) bool { +### 解二:迭代 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def isSymmetric(self, root: TreeNode) -> bool: + if root is None: + return True + queue = [] + queue.append(root.left) + queue.append(root.right) + while len(queue) > 0: + left = queue[0] + del queue[0] + right = queue[0] + del queue[0] + + if left is None: + if right is None: + pass + else: + return False + else: + if right is None: + return False + else: + queue.append(left.left) + queue.append(right.right) + queue.append(left.right) + queue.append(right.left) + if left.val != right.val: + return False + + return True +``` + +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func isSymmetric(root *TreeNode) bool { + queue := make([]*TreeNode, 0) + if root == nil { + return true + } + queue = append(queue, root.Left) + queue = append(queue, root.Right) + for len(queue) > 0 { + left := queue[0] + queue = queue[1:] + right := queue[0] + queue = queue[1:] + + if left == nil { + if right != nil { + return false + } + } else { + if right == nil { + return false + } else { + queue = append(queue, left.Left) + queue = append(queue, right.Right) + queue = append(queue, left.Right) + queue = append(queue, right.Left) + if left.Val != right.Val { + return false + } + } + } + } + return true +} +``` + + + ## 687. 最长同值路径 [原题链接](https://leetcode-cn.com/problems/longest-univalue-path/description/) From 0cf5ca54095734f7881839d5b028013f50e70216 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 29 Feb 2020 21:28:52 +0800 Subject: [PATCH 051/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20112.=20=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E6=80=BB=E5=92=8C=20=E8=A1=A5=E5=85=85=20golang=20?= =?UTF-8?q?=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index b8ec6dd62..dc9d77199 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -392,6 +392,10 @@ class Solution(object): - 最终相加和为 sum - False 的条件为:一直找到叶子节点了还是没有找到那个节点 + + +#### **Python** + ```python class Solution(object): def hasPathSum(self, root, sum): @@ -401,12 +405,39 @@ class Solution(object): :rtype: bool """ if root is None: + # 如果传入节点为空则直接返回 False return False if root.left is None and root.right is None and root.val == sum: return True return self.hasPathSum(root.left, sum - root.val) or self.hasPathSum(root.right, sum - root.val) ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func hasPathSum(root *TreeNode, sum int) bool { + if root == nil { + return false + } + // 该节点为叶子节点 + if root.Left == nil && root.Right == nil { + return sum == root.Val + } + // 递归 + return hasPathSum(root.Left, sum - root.Val) || hasPathSum(root.Right, sum - root.Val) +} +``` + + + ## 226. 翻转二叉树 [原题链接](https://leetcode-cn.com/problems/invert-binary-tree/description/) From f5b7e1753b4379ef7f574660a9ee07e80d93135a Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 1 Mar 2020 14:47:17 +0800 Subject: [PATCH 052/181] =?UTF-8?q?=F0=9F=90=B1(queue):=20232.=20=E7=94=A8?= =?UTF-8?q?=E6=A0=88=E5=AE=9E=E7=8E=B0=E9=98=9F=E5=88=97=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 437 ++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index 315685df8..d92f4a5b3 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -401,6 +401,443 @@ class MyStack: return True ``` +### 双队列解法一 + +定义两个辅助队列 `queue1` 与 `queue2`,使用一个变量 `top_element` 记录栈顶元素。 + +- `push()`:将元素入队 `queue1` +- `pop()`: + - 将 `queue1` 内所有元素全部出队,除最后一个元素外,其余入队 `queue2`,而后删除最后一个元素并返回 + - 更新 `top_element` + - 调换 `queue1` 与 `queue2` +- `top()`:返回 `top_elenemt` +- `empty()`:判断 `queue1` 的长度 + + + +#### **Python** + +```python +class MyStack: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.queue1 = [] + self.queue2 = [] + self.top_element = 0 + + def push(self, x: int) -> None: + """ + Push element x onto stack. + """ + self.queue1.append(x) + self.top_element = x + + def pop(self) -> int: + """ + Removes the element on top of the stack and returns that element. + """ + # 把 queue1 里的元素取出,留下一个,其余塞入 queue2 中 + length1 = len(self.queue1) + for i in range(length1 - 1): + item = self.queue1[0] + del self.queue1[0] + self.queue2.append(item) + self.top = item + target = self.queue1[0] + del self.queue1[0] + # 交换 queue1 与 queue2 + self.queue1 = self.queue2 + self.queue2 = [] + return target + + def top(self) -> int: + """ + Get the top element. + """ + # length1 = len(self.queue1) + # for i in range(length1): + # item = self.queue1[0] + # del self.queue1[0] + # self.queue2.append(item) + # self.queue1 = self.queue2 + # self.queue2 = [] + # return item + return self.top_element + + def empty(self) -> bool: + """ + Returns whether the stack is empty. + """ + return len(self.queue1) == 0 + + +# Your MyStack object will be instantiated and called as such: +# obj = MyStack() +# obj.push(x) +# param_2 = obj.pop() +# param_3 = obj.top() +# param_4 = obj.empty() +``` + +#### **Go** + +```go +type MyStack struct { + Queue1 []int + Queue2 []int + TopElement int +} + + +/** Initialize your data structure here. */ +func Constructor() MyStack { + var myStack MyStack + return myStack +} + + +/** Push element x onto stack. */ +func (this *MyStack) Push(x int) { + this.Queue1 = append(this.Queue1, x) + this.TopElement = x +} + + +/** Removes the element on top of the stack and returns that element. */ +func (this *MyStack) Pop() int { + length1 := len(this.Queue1) + for i := 0; i < length1 - 1; i++ { + // 取出每个元素 + item := this.Queue1[0] + this.TopElement = item + // 删除元素 + this.Queue1 = this.Queue1[1:] + // 入队列 2 + this.Queue2 = append(this.Queue2, item) + } + target := this.Queue1[0] + // 交换 + this.Queue1 = this.Queue2 + this.Queue2 = make([]int, 0) + return target +} + + +/** Get the top element. */ +func (this *MyStack) Top() int { + return this.TopElement +} + + +/** Returns whether the stack is empty. */ +func (this *MyStack) Empty() bool { + return len(this.Queue1) == 0 +} + + +/** + * Your MyStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(x); + * param_2 := obj.Pop(); + * param_3 := obj.Top(); + * param_4 := obj.Empty(); + */ +``` + + + +- 时间复杂度:压入 $O(1)$,弹出 $O(n)$ + +### 双队列解法二 + +定义两个辅助队列 `queue1` 与 `queue2`,使用一个变量 `top_element` 记录栈顶元素。 + +- `push()`: + - 将元素入队 `queue2`,此时 `queue2` 中的首个元素为栈顶元素 + - 更新 `top_element` + - 此时若 `queue1` 不为空,则让 `queue1` 中的元素逐个出队并加入 `queue2` 中 +- `pop()`: `queue1` 首个元素出队,更新 `top_element` +- `top()`: 返回 `top_element` +- `empty()`: 判断 `queue1` 长度 + + + +#### **Python** + +```python +class MyStack: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.queue1 = [] + self.queue2 = [] + self.top_element = 0 + + + def push(self, x: int) -> None: + """ + Push element x onto stack. + """ + # 更新栈顶元素 + self.top_element = x + # 加入 queue2 中 + self.queue2.append(x) + if not self.empty(): + # 如果 queue1 不为空,取出元素并加入 queue2 + length1 = len(self.queue1) + for i in range(length1): + self.queue2.append(self.queue1[0]) + del self.queue1[0] + # 交换 + self.queue1 = self.queue2 + self.queue2 = [] + + + def pop(self) -> int: + """ + Removes the element on top of the stack and returns that element. + """ + target = self.queue1[0] + del self.queue1[0] + # 更新 top_element + if not self.empty(): + self.top_element = self.queue1[0] + return target + + + def top(self) -> int: + """ + Get the top element. + """ + return self.top_element + + + def empty(self) -> bool: + """ + Returns whether the stack is empty. + """ + return len(self.queue1) == 0 + + +# Your MyStack object will be instantiated and called as such: +# obj = MyStack() +# obj.push(x) +# param_2 = obj.pop() +# param_3 = obj.top() +# param_4 = obj.empty() +``` + +#### **Go** + +```go +type MyStack struct { + Queue1 []int + Queue2 []int + TopElement int +} + + +/** Initialize your data structure here. */ +func Constructor() MyStack { + var myStack MyStack + return myStack +} + + +/** Push element x onto stack. */ +func (this *MyStack) Push(x int) { + this.Queue2 = append(this.Queue2, x) + // 更新栈顶元素 + this.TopElement = x + if !this.Empty() { + length1 := len(this.Queue1) + for i := 0; i < length1; i++ { + this.Queue2 = append(this.Queue2, this.Queue1[0]) + // 删除元素 + this.Queue1 = this.Queue1[1:] + } + } + // 交换 + this.Queue1 = this.Queue2 + this.Queue2 = make([]int, 0) +} + + +/** Removes the element on top of the stack and returns that element. */ +func (this *MyStack) Pop() int { + target := this.Queue1[0] + this.Queue1 = this.Queue1[1:] + if !this.Empty() { + // 更新栈顶元素 + this.TopElement = this.Queue1[0] + } + return target +} + + +/** Get the top element. */ +func (this *MyStack) Top() int { + return this.TopElement +} + + +/** Returns whether the stack is empty. */ +func (this *MyStack) Empty() bool { + return len(this.Queue1) == 0 +} + + +/** + * Your MyStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(x); + * param_2 := obj.Pop(); + * param_3 := obj.Top(); + * param_4 := obj.Empty(); + */ +``` + + + +- 时间复杂度:压入 $O(n)$,弹出 $O(1)$ + +### 单队列解法三 + +定义辅助队列 `queue`。 + +- `push()`: + - 将元素入队 + - 除新入队元素,将其他元素从队首取出,再从队尾入队(完成反序)。此时队首元素即为新入队元素 +- `pop()`:`queue` 首个元素出队 +- `top()`:获取 `queue` 首个元素 +- `empty()`:判断 `queue` 长度 + + + +#### **Python** + +```python +class MyStack: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.queue = [] + + + def push(self, x: int) -> None: + """ + Push element x onto stack. + """ + self.queue.append(x) + # 队列反序 + length = len(self.queue) + for i in range(length - 1): + first = self.queue[0] + del self.queue[0] + self.queue.append(first) + + + def pop(self) -> int: + """ + Removes the element on top of the stack and returns that element. + """ + target = self.queue[0] + del self.queue[0] + return target + + + def top(self) -> int: + """ + Get the top element. + """ + return self.queue[0] + + + def empty(self) -> bool: + """ + Returns whether the stack is empty. + """ + return len(self.queue) == 0 + + +# Your MyStack object will be instantiated and called as such: +# obj = MyStack() +# obj.push(x) +# param_2 = obj.pop() +# param_3 = obj.top() +# param_4 = obj.empty() +``` + +#### **Go** + +```go +type MyStack struct { + Queue []int +} + + +/** Initialize your data structure here. */ +func Constructor() MyStack { + var myStack MyStack + return myStack +} + + +/** Push element x onto stack. */ +func (this *MyStack) Push(x int) { + this.Queue = append(this.Queue, x) + length := len(this.Queue) + for i := 0; i < length - 1; i++ { + // 反序操作 + first := this.Queue[0] + this.Queue = this.Queue[1:] + this.Queue = append(this.Queue, first) + } +} + + +/** Removes the element on top of the stack and returns that element. */ +func (this *MyStack) Pop() int { + target := this.Queue[0] + this.Queue = this.Queue[1:] + return target +} + + +/** Get the top element. */ +func (this *MyStack) Top() int { + return this.Queue[0] +} + + +/** Returns whether the stack is empty. */ +func (this *MyStack) Empty() bool { + return len(this.Queue) == 0 +} + + +/** + * Your MyStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(x); + * param_2 := obj.Pop(); + * param_3 := obj.Top(); + * param_4 := obj.Empty(); + */ +``` + + + +- 时间复杂度:压入 $O(n)$,弹出 $O(1)$ + ## 331. 验证二叉树的前序序列化 [原题链接](https://leetcode-cn.com/problems/verify-preorder-serialization-of-a-binary-tree/) From 62d8363ef0e6d0e453f56b80f73976b3f4dadcc2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 2 Mar 2020 22:07:33 +0800 Subject: [PATCH 053/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20105.=20=E4=BB=8E?= =?UTF-8?q?=E5=89=8D=E5=BA=8F=E4=B8=8E=E4=B8=AD=E5=BA=8F=E9=81=8D=E5=8E=86?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E6=9E=84=E9=80=A0=E4=BA=8C=E5=8F=89=E6=A0=91?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=20golang=20=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index dc9d77199..12130ee3f 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -183,6 +183,10 @@ func max(a int, b int) int { 整个过程我们可以用递归来完成。 + + +#### **Python** + ```python # Definition for a binary tree node. # class TreeNode(object): @@ -212,6 +216,45 @@ class Solution(object): return root ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func buildTree(preorder []int, inorder []int) *TreeNode { + if len(preorder) == 0 { + return nil + } + root := new(TreeNode) + // 前序遍历第一个是根元素 + root.Val = preorder[0] + // 找到位置 + rootIndex := findRootIndex(inorder, root.Val) + // 构造左右子树 + root.Left = buildTree(preorder[1:1+rootIndex], inorder[:rootIndex]) + root.Right = buildTree(preorder[1+rootIndex:], inorder[rootIndex+1:]) + + return root +} + +func findRootIndex(inorder []int, rootVal int) int { + for i, val := range inorder { + if val == rootVal { + return i + } + } + return 0 +} +``` + + + ## 106. 从中序与后序遍历序列构造二叉树 [原题链接](https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) From d411d178bd70727b6b1588eee3bedcbf79db9fb5 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 3 Mar 2020 23:06:39 +0800 Subject: [PATCH 054/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2010.01.=20=E5=90=88=E5=B9=B6=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E7=9A=84=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/double-pointer/README.md | 74 +++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/algorithm/double-pointer/README.md b/docs/algorithm/double-pointer/README.md index 63d2acde8..61e72c7fe 100644 --- a/docs/algorithm/double-pointer/README.md +++ b/docs/algorithm/double-pointer/README.md @@ -219,4 +219,78 @@ class Solution { } ``` + + +## 面试题 10.01. 合并排序的数组 + +[原题链接](https://leetcode-cn.com/problems/sorted-merge-lcci/) + +### 逆向双指针 + +- 定义两个指针 `cur_a` 与 `cur_b`,分别指向 A 数组与 B 数组的尾部,再定义一个指针 `cur` 指向 A 数组当前可以赋值的元素位置 +- 比较 `cur_a` 与 `cur_b` 指向的两个元素,把较大的元素赋值给 `cur` 所在位置 + + + +#### **Python** + +```python +class Solution: + def merge(self, A: List[int], m: int, B: List[int], n: int) -> None: + """ + Do not return anything, modify A in-place instead. + """ + # 双指针:指向两个比较的数 + cur_a = m - 1 + cur_b = n - 1 + # 指向要赋值的位置 + cur = len(A) - 1 + + while cur_a >= 0 and cur_b >= 0: + a = A[cur_a] + b = B[cur_b] + # 取较大的放在后面 + if a >= b: + A[cur] = a + cur_a -= 1 + else: + A[cur] = b + cur_b -= 1 + cur -= 1 + + while cur_b >= 0: + A[cur] = B[cur_b] + cur_b -= 1 + cur -= 1 +``` + +#### **Go** + +```go +func merge(A []int, m int, B []int, n int) { + curA := m - 1 + curB := n - 1 + cur := len(A) - 1 + + for curA >= 0 && curB >= 0 { + a := A[curA] + b := B[curB] + if a >= b { + A[cur] = a + curA -= 1 + } else { + A[cur] = b + curB -= 1 + } + cur -= 1 + } + + for curB >= 0 { + A[cur] = B[curB] + curB -= 1 + cur -= 1 + } +} +``` + \ No newline at end of file From 281b3f770a39639ea06b95cbf0e25a5a517fa090 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 3 Mar 2020 23:13:35 +0800 Subject: [PATCH 055/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20116.=20=E5=A1=AB?= =?UTF-8?q?=E5=85=85=E6=AF=8F=E4=B8=AA=E8=8A=82=E7=82=B9=E7=9A=84=E4=B8=8B?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8F=B3=E4=BE=A7=E8=8A=82=E7=82=B9=E6=8C=87?= =?UTF-8?q?=E9=92=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 12130ee3f..9d5077ea5 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -481,6 +481,48 @@ func hasPathSum(root *TreeNode, sum int) bool { +## 116. 填充每个节点的下一个右侧节点指针 + +[原题链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/) + +### 解一:递归 + +- `root.left.next = root.right` +- 利用已经处理好的 `next` 指针:`root.right.next = root.next.left` + + + +#### **Python** + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" +class Solution: + def connect(self, root: 'Node') -> 'Node': + self.handler(root) + return root + + def handler(self, root): + if root is None or root.left is None: + return None + root.left.next = root.right + if root.next is not None: + root.right.next = root.next.left + # 关联节点 + self.connect(root.left) + # 关联右节点 + self.connect(root.right) +``` + + + ## 226. 翻转二叉树 [原题链接](https://leetcode-cn.com/problems/invert-binary-tree/description/) From 22185bee6bdffd6fe7d9b086479fa01f5819b95e Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 4 Mar 2020 20:33:53 +0800 Subject: [PATCH 056/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20117.=20=E5=A1=AB?= =?UTF-8?q?=E5=85=85=E6=AF=8F=E4=B8=AA=E8=8A=82=E7=82=B9=E7=9A=84=E4=B8=8B?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=8F=B3=E4=BE=A7=E8=8A=82=E7=82=B9=E6=8C=87?= =?UTF-8?q?=E9=92=88=20II=20=E8=A1=A5=E5=85=85=E9=80=92=E5=BD=92=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/bfs/README.md | 62 +++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/tree/bfs/README.md b/docs/data-structure/tree/bfs/README.md index e278097a1..ab8c1af97 100644 --- a/docs/data-structure/tree/bfs/README.md +++ b/docs/data-structure/tree/bfs/README.md @@ -125,7 +125,7 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/) -### 思路 +### 解一:实用了额外空间 层次遍历的变种考点。 @@ -170,6 +170,66 @@ class Solution(object): return root ``` +### 解二:常数空间 + 递归 + +- 不断找到下一个可关联的右侧不为空节点 +- 注意:先构造右子树 + + + +#### **Python** + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" +class Solution: + def connect(self, root: 'Node') -> 'Node': + self.handler(root) + return root + + def handler(self, root): + if root is None or (root.left is None and root.right is None): + return + + # 处理左节点 + if root.left is not None: + if root.right is not None: + # 如果存在右节点:指向右节点 + root.left.next = root.right + else: + # 如果不存在右节点;一直往下找到第一个存在的右侧节点 + root.left.next = self.get_next(root) + + # 处理右节点 + # 使用 next 指针 + if root.right is not None: + root.right.next = self.get_next(root) + + # 先递归右子树 + self.handler(root.right) + self.handler(root.left) + + + def get_next(self, root): + next_node = root.next + while next_node is not None: + if next_node.left is not None: + return next_node.left + if next_node.right is not None: + return next_node.right + next_node = next_node.next + return None +``` + + + ## 513. 找树左下角的值 [原题链接](https://leetcode-cn.com/problems/find-bottom-left-tree-value/comments/) From 5f6aea384a13d0597dc2ba81cd45b6441ef826c7 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 5 Mar 2020 23:33:49 +0800 Subject: [PATCH 057/181] =?UTF-8?q?=F0=9F=90=B1(math):=201103.=20=E5=88=86?= =?UTF-8?q?=E7=B3=96=E6=9E=9C=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/math/README.md | 47 ++++++++++++ docs/data-structure/tree/recursion/README.md | 46 ++++++++++++ docs/weekly/README.md | 78 +++++++++++++++++++- 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/math/README.md b/docs/algorithm/math/README.md index 9f18b4d0e..1bebec5bc 100644 --- a/docs/algorithm/math/README.md +++ b/docs/algorithm/math/README.md @@ -484,6 +484,53 @@ class Solution: return "x=" + str(-num // x_count) ``` +## 1103. 分糖果 II + +[原题链接](https://leetcode-cn.com/problems/distribute-candies-to-people/) + +### 等差数列 + +```python +class Solution: + def distributeCandies(self, candies: int, num_people: int) -> List[int]: + s = 0 + x = 1 + people = 0 + while s + x < candies: + people += 1 + s += x + x += 1 + # 只够发到 x - 1 个人,第 x 个人可能没有足额糖果 + + # 计算可以发几轮(总轮数) + r = people // num_people + # print(people, r) + # 多发一排人数 + other = people % num_people + # 最后可能有剩余糖果分给最后一个人 + + # 等差数列 d = n + # 给每个小朋友发 + res = [0 for _ in range(num_people)] + for i in range(num_people): + res[i] = (i + 1) * r + (r * (r - 1) * num_people) // 2 + + # 给最后一排分糖果 + other_begin = r * num_people + 1 + for i in range(other): + res[i] += other_begin + other_begin += 1 + + if s < candies: + index = i + 1 + if i + 1 == num_people: + index = 0 + res[index] += candies - s + + # print(res) + return res +``` + ## 1276. 不浪费原料的汉堡制作方案 [原题链接](https://leetcode-cn.com/problems/number-of-burgers-with-no-waste-of-ingredients/) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 9d5077ea5..b9d02fb4a 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -548,6 +548,52 @@ class Solution(object): return root ``` +## 236. 二叉树的最近公共祖先 + +[原题链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/)(同 [面试题68 - II. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/)) + +### 递归法 + +因为找两个节点的公共祖先,所以从上往下递归遍历。 + +- 如果 `root` 等于 `q` 或 `p` 其中之一,则直接返回 `root` +- 接着查找 `root` 的左右子树 +- 如果 `p` 与 `q` 不在左子树中,则必定在右子树中 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: + if root is None or root == p or root == q: + return root + + # 在左子树找 + left = self.lowestCommonAncestor(root.left, p, q) + # 在右子树找 + right = self.lowestCommonAncestor(root.right, p, q) + + if left is None and right is None: + return None + if left is None: + return right + if right is None: + return left + + return root +``` + + + ## 337. 打家劫舍 III [原题链接](https://leetcode-cn.com/problems/house-robber-iii/description/) diff --git a/docs/weekly/README.md b/docs/weekly/README.md index 3ca7e013a..d81137f54 100644 --- a/docs/weekly/README.md +++ b/docs/weekly/README.md @@ -420,7 +420,7 @@ class Solution(object): [原题链接](https://leetcode-cn.com/contest/weekly-contest-124/problems/rotting-oranges/) -### 思路 +#### 思路 基本思路:从 `1` 出发搜索,返回找到 `2` 需要走的步数(即分钟数),求得该步数的最大值。 @@ -474,6 +474,82 @@ class Solution(object): return float('inf') ``` +#### 20200304 重写 + + + +#### **Python** + +```python +class Solution: + def orangesRotting(self, grid: List[List[int]]) -> int: + bad_queue = [] + bad = 0 + good = 0 + # 计算橘子情况 + for i in range(len(grid)): + for j in range(len(grid[0])): + if grid[i][j] == 1: + good += 1 + elif grid[i][j] == 2: + bad += 1 + # 入队 + bad_queue.append([i, j]) + + # 根据统计情况返回 + if good == 0: + # 没有新鲜的橘子 + return 0 + if bad == 0: + # 没有坏的橘子 + return -1 + + res = 0 + i_length = len(grid) + j_length = len(grid[0]) + while len(bad_queue) > 0: + # 分钟数 + res += 1 + # 取出第一批橘子 + for i in range(len(bad_queue)): + first = bad_queue[0] + del bad_queue[0] + # 开始感染其他橘子 + i = first[0] + j = first[1] + + if i - 1 >= 0 and grid[i - 1][j] == 1: + good -= 1 + grid[i - 1][j] = 2 + bad_queue.append([i - 1, j]) + if i + 1 < i_length and grid[i + 1][j] == 1: + good -= 1 + grid[i + 1][j] = 2 + bad_queue.append([i + 1, j]) + if j - 1 >= 0 and grid[i][j - 1] == 1: + good -= 1 + grid[i][j - 1] = 2 + bad_queue.append([i, j - 1]) + if j + 1 < j_length and grid[i][j + 1] == 1: + good -= 1 + grid[i][j + 1] = 2 + bad_queue.append([i, j + 1]) + # 是否已经没有新鲜橘子 + if good <= 0: + return res + + return -1 if good > 0 else res +``` + +#### **Go** + +```go + + +``` + + + ---- ## 第 129 场周赛 From 04f2d9033c372e2275d4863de299afac8ea90063 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 6 Mar 2020 23:58:48 +0800 Subject: [PATCH 058/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20297.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=BA=8F=E5=88=97=E5=8C=96=E4=B8=8E?= =?UTF-8?q?=E5=8F=8D=E5=BA=8F=E5=88=97=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/bfs/README.md | 97 ++++++++++++++++++++++++++ docs/offer/README.md | 23 ++++++ 2 files changed, 120 insertions(+) diff --git a/docs/data-structure/tree/bfs/README.md b/docs/data-structure/tree/bfs/README.md index ab8c1af97..821f505e6 100644 --- a/docs/data-structure/tree/bfs/README.md +++ b/docs/data-structure/tree/bfs/README.md @@ -230,6 +230,103 @@ class Solution: +## 297. 二叉树的序列化与反序列化 + +[原题链接](https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/) + +### BFS:层序遍历 + +- 序列化:将题中二叉树利用辅助队列层序遍历为 `1,2,3,null,null,4,5` +- 反序列化:字符串转为数组,将第一个节点入队列,依旧以队列的方式进行反序列化 + +```python +# Definition for a binary tree node. +# class TreeNode(object): +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Codec: + def serialize(self, root): + """Encodes a tree to a single string. + + :type root: TreeNode + :rtype: str + """ + str_list = [] + queue = [] + queue.append(root) + while len(queue) > 0: + q_length = len(queue) + for i in range(q_length): + # 取出队列头部节点 + first = queue[0] + del queue[0] + if first is None: + str_list.append("N") + continue + str_list.append(str(first.val)) + # 左右节点入队列 + queue.append(first.left) + queue.append(first.right) + # print(str_list) + return ','.join(str_list) + + def deserialize(self, data): + """Decodes your encoded data to tree. + + :type data: str + :rtype: TreeNode + """ + str_list = data.split(',') + # 取出第一个节点 + first = str_list[0] + root = self.get_node(first) + queue = [] + queue.append(root) + del str_list[0] + while len(queue) > 0: + q_length = len(queue) + for i in range(q_length): + first = queue[0] + del queue[0] + if first is None: + continue + # 构造它的左右节点 + str_list_length = len(str_list) + if str_list_length >= 2: + left_node = self.get_node(str_list[0]) + del str_list[0] + right_node = self.get_node(str_list[0]) + del str_list[0] + elif str_list_length == 1: + left_node = self.get_node(str_list[0]) + right_node = None + del str_list[0] + else: + left_node = None + right_node = None + first.left = left_node + first.right = right_node + if left_node is not None: + queue.append(left_node) + if right_node is not None: + queue.append(right_node) + + return root + + def get_node(self, root_val): + if root_val == 'N': + return None + else: + return TreeNode(int(root_val)) + +# Your Codec object will be instantiated and called as such: +# codec = Codec() +# codec.deserialize(codec.serialize(root)) +``` + ## 513. 找树左下角的值 [原题链接](https://leetcode-cn.com/problems/find-bottom-left-tree-value/comments/) diff --git a/docs/offer/README.md b/docs/offer/README.md index aa6f05feb..519e53750 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -221,4 +221,27 @@ class Solution: # 断开链接 head.next = None return cur +``` + +## 面试题57 - II. 和为s的连续正数序列 + +[原题链接](https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/) + +### 滑动窗口法 + +```python +class Solution: + def findContinuousSequence(self, target: int) -> List[List[int]]: + s = 0 + tmp = [] + res = [] + for i in range(1, target): + s += i + tmp.append(i) + while s >= target: + if s == target: + res.append(tmp[:]) + s -= tmp[0] + del tmp[0] + return res ``` \ No newline at end of file From 59c26e70a99e5703997da911ca4467327afb114f Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 7 Mar 2020 22:02:58 +0800 Subject: [PATCH 059/181] =?UTF-8?q?=F0=9F=90=B1(tree):=2098.=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=80=92=E5=BD=92=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/dfs/README.md | 61 +++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/tree/dfs/README.md b/docs/data-structure/tree/dfs/README.md index a136a5917..0e031374e 100644 --- a/docs/data-structure/tree/dfs/README.md +++ b/docs/data-structure/tree/dfs/README.md @@ -139,7 +139,7 @@ func inorderTraversal(root *TreeNode) []int { [原题链接](https://leetcode-cn.com/problems/validate-binary-search-tree/submissions/) -### 思路 +### 解一:中序遍历 中序遍历为升序 @@ -174,6 +174,65 @@ class Solution(object): return ``` +### 解二:递归 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + return self.helper(root, None, None) + + def helper(self, root, low, high): + if root is None: + return True + if low is not None and root.val <= low: + return False + if high is not None and root.val >= high: + return False + return self.helper(root.left, low, root.val) and self.helper(root.right, root.val, high) +``` + +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func isValidBST(root *TreeNode) bool { + return helper(root, -1<<63, 1<<63-1) +} + +func helper(root *TreeNode, low int, high int) bool { + if root == nil { + return true + } + if root.Val <= low { + return false + } + if root.Val >= high { + return false + } + return helper(root.Left, low, root.Val) && helper(root.Right, root.Val, high) +} +``` + + + ## 105. 从前序与中序遍历序列构造二叉树 [原题链接](https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) From 35d313fdcc4d04fce8622bb33fe6a6145c4f63f3 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 7 Mar 2020 23:33:21 +0800 Subject: [PATCH 060/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=9859=20-=20II.=20=E9=98=9F=E5=88=97=E7=9A=84?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 112 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/docs/offer/README.md b/docs/offer/README.md index 519e53750..9cbdb843c 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -244,4 +244,114 @@ class Solution: s -= tmp[0] del tmp[0] return res -``` \ No newline at end of file +``` + +## 面试题59 - II. 队列的最大值 + +[原题链接](https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/) + +### 思路 + +用一个双端队列,将队列最大值永远放在双端队列的队首。 + + + +#### **Python** + +```python +class MaxQueue: + + def __init__(self): + self.m = 0 + self.queue = [] + self.deque = [] + + def max_value(self) -> int: + if len(self.queue) == 0: + return -1 + return self.deque[0] + + def push_back(self, value: int) -> None: + self.queue.append(value) + # 维护 deque + while len(self.deque) > 0 and self.deque[-1] < value: + # 从尾部删除这个值 + self.deque.pop() + self.deque.append(value) + + def pop_front(self) -> int: + if len(self.queue) == 0: + return -1 + first = self.queue[0] + del self.queue[0] + if first == self.deque[0]: + del self.deque[0] + return first + +# Your MaxQueue object will be instantiated and called as such: +# obj = MaxQueue() +# param_1 = obj.max_value() +# obj.push_back(value) +# param_3 = obj.pop_front() +``` + +#### **Go** + +```go +type MaxQueue struct { + Queue []int + Deque []int +} + + +func Constructor() MaxQueue { + var maxQueue MaxQueue + maxQueue.Queue = make([]int, 0) + maxQueue.Deque = make([]int, 0) + return maxQueue +} + + +func (this *MaxQueue) Max_value() int { + if len(this.Queue) == 0 { + return -1 + } + return this.Deque[0] +} + + +func (this *MaxQueue) Push_back(value int) { + // 维护双端队列 + this.Queue = append(this.Queue, value) + for len(this.Deque) > 0 && value > this.Deque[len(this.Deque) - 1] { + // 最后一个值出队 + this.Deque = this.Deque[:len(this.Deque) - 1] + } + this.Deque = append(this.Deque, value) +} + + +func (this *MaxQueue) Pop_front() int { + if len(this.Queue) == 0 { + return -1 + } + first := this.Queue[0] + if first == this.Deque[0] { + // 删除第一个元素 + this.Deque = this.Deque[1:] + } + this.Queue = this.Queue[1:] + return first +} + + +/** + * Your MaxQueue object will be instantiated and called as such: + * obj := Constructor(); + * param_1 := obj.Max_value(); + * obj.Push_back(value); + * param_3 := obj.Pop_front(); + */ +``` + + \ No newline at end of file From 68e8b5921754554d41be7aa405aa6f3e18319256 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 9 Mar 2020 10:15:23 +0800 Subject: [PATCH 061/181] =?UTF-8?q?=F0=9F=90=B1(dp):=20121.=20=E4=B9=B0?= =?UTF-8?q?=E5=8D=96=E8=82=A1=E7=A5=A8=E7=9A=84=E6=9C=80=E4=BD=B3=E6=97=B6?= =?UTF-8?q?=E6=9C=BA=20=E8=A1=A5=E5=85=85=20golang=20=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 7e0cb270d..5c53db27c 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1028,6 +1028,10 @@ class Solution: 2019.01.05 复盘打卡 + + +#### **Python** + ```python class Solution(object): def maxProfit(self, prices): @@ -1051,7 +1055,30 @@ class Solution(object): return max_val ``` +#### **Go** + +```go +func maxProfit(prices []int) int { + dayCount := len(prices) + if dayCount == 0 { + return 0 + } + res := 0 + min := prices[0] + for i := 1; i < dayCount; i++ { + get := prices[i] - min + if get > res { + res = get + } + if prices[i] < min { + min = prices[i] + } + } + return res +} +``` + ## 167. 两数之和 II - 输入有序数组 From 0e94c2b9484eaf24be25c4e862e6071224789616 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 9 Mar 2020 10:37:02 +0800 Subject: [PATCH 062/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20700.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD=E7=9A=84=E6=90=9C?= =?UTF-8?q?=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 67 ++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index b9d02fb4a..b622a051f 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -935,6 +935,73 @@ class Solution(object): return l_val ``` +## 700. 二叉搜索树中的搜索 + +[原题链接](https://leetcode-cn.com/problems/search-in-a-binary-search-tree/) + +### 递归 + +递归设计: + +- 递归函数作用:返回目标节点 +- 函数返回时机: + - 节点为空 + - 找到目标节点 +- 递归调用时机:搜索左子树或右子树时 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def searchBST(self, root: TreeNode, val: int) -> TreeNode: + if root is None: + return None + root_val = root.val + if root_val == val: + return root + if val < root.val: + return self.searchBST(root.left, val) + if val > root.val: + return self.searchBST(root.right, val) +``` + +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func searchBST(root *TreeNode, val int) *TreeNode { + if root == nil { + return nil + } + rootVal := root.Val + if rootVal == val { + return root + } else if rootVal < val { + return searchBST(root.Right, val) + } else { + return searchBST(root.Left, val) + } +} +``` + + + ## 783. 二叉搜索树结点最小距离 [原题链接](https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/) From af55013a17cdc11260b8b67be7b81aced64392b6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 10 Mar 2020 14:58:33 +0800 Subject: [PATCH 063/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20543.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E7=9B=B4=E5=BE=84=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=20golang=20=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index b622a051f..bc4008bd9 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -760,6 +760,10 @@ class Solution: 和 [104](/tree/104.md) 的套路一样,加上取 max 逻辑而已。 + + +#### **Python** + ```python class Solution(object): max_length = 0 @@ -783,6 +787,45 @@ class Solution(object): return max(l, r) + 1 ``` +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +var res int + +func diameterOfBinaryTree(root *TreeNode) int { + helper(root) + return res +} + +func helper(root *TreeNode) int { + if root == nil { + return 0 + } + leftDepth := helper(root.Left) + rightDepth := helper(root.Right) + length := leftDepth + rightDepth + res = getMax(res, length) + return getMax(leftDepth, rightDepth) + 1 +} + +func getMax(a int, b int) int { + if a > b { + return a + } + return b +} +``` + + + ## 572. 另一个树的子树 [原题链接](https://leetcode-cn.com/problems/subtree-of-another-tree/description/) From 081c0c59b6e971cd88e169a5f8efaba082096355 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 11 Mar 2020 21:48:07 +0800 Subject: [PATCH 064/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20450.=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index bc4008bd9..3695284f9 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -715,6 +715,69 @@ class Solution(object): return result ``` +## 450. 删除二叉搜索树中的节点 + +[原题链接](https://leetcode-cn.com/problems/delete-node-in-a-bst/) + +### 思路 + +要删除的节点共有三种情况: + +1. 是叶节点:直接删除 +2. 有右子树:找它的后继节点交换(值)并删除后继节点 +3. 有左子树:找到它的前驱节点交换(值)并删除前驱节点 + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def deleteNode(self, root: TreeNode, key: int) -> TreeNode: + # 找到节点 + if root is None: + return None + if key > root.val: + # 找右子树 + root.right = self.deleteNode(root.right, key) + elif key < root.val: + # 找左子树 + root.left = self.deleteNode(root.left, key) + else: + # 找到节点 + if root.left is None and root.right is None: + # 删除的节点是叶子节点 + root = None + elif root.right is not None: + # 有右子树,找后继节点 + root.val = self.successor(root) + # 删除这个后继节点 + root.right = self.deleteNode(root.right, root.val) + else: + # 有左子树,找前驱节点 + root.val = self.predecessor(root) + root.left = self.deleteNode(root.left, root.val) + + return root + + def successor(self, root): + # 后继节点:比节点大的最小节点 + root = root.right + while root.left is not None: + root = root.left + return root.val + + def predecessor(self, root): + # 前驱节点 + root = root.left + while root.right is not None: + root = root.right + return root.val +``` + ## 538. 把二叉搜索树转换为累加树 [原题链接](https://leetcode-cn.com/problems/convert-bst-to-greater-tree/) From 81c5068293e8deae7a2c8d70b38eaff61a763ad5 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 12 Mar 2020 00:09:08 +0800 Subject: [PATCH 065/181] =?UTF-8?q?=F0=9F=90=B1(array):=201013.=20?= =?UTF-8?q?=E5=B0=86=E6=95=B0=E7=BB=84=E5=88=86=E6=88=90=E5=92=8C=E7=9B=B8?= =?UTF-8?q?=E7=AD=89=E7=9A=84=E4=B8=89=E4=B8=AA=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 45 +++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 5c53db27c..4ad6af38d 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2663,4 +2663,49 @@ class Solution(object): return tmp_string ``` +## 1013. 将数组分成和相等的三个部分 +[原题链接](https://leetcode-cn.com/problems/partition-array-into-three-parts-with-equal-sum/) + +### 思路 + +1. 数组求和,看是否可以整除三,不能整除则直接返回 `false` +2. 双指针指向数组前后,前后都分别开始找累加和等于目标值的部分,如果前后都能找到,则中间的自动就找到了 + +注意问题: + +1. 存在 `[1,-1,1,-1]` 这样的用例,需要判断双指针最终位置,相距是否大于 1,即中间是否还有位置 +2. 目标值可以为 0,所以左右区间的数据应当初始化为 `A[0]` 与 `A[length - 1]` + +```python +class Solution: + def canThreePartsEqualSum(self, A: List[int]) -> bool: + # 求总和 + s = sum(A) + if s % 3 != 0: + return False + part = s // 3 + + # 双指针 + i = 0 + j = len(A) - 1 + # 计算左右区间和 + left_part = A[i] + right_part = A[j] + res = False + while i < j: + if left_part != part: + i += 1 + left_part += A[i] + + if right_part != part: + j -= 1 + right_part += A[j] + + if left_part == part and right_part == part: + res = True + break + # print(i, j) + # 处理特殊情况:[1,-1,1,-1] + return res and j - i > 1 +``` \ No newline at end of file From 6bce0ec619a2f0792934d96a442706973fc55cbd Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 12 Mar 2020 22:40:45 +0800 Subject: [PATCH 066/181] =?UTF-8?q?=F0=9F=90=B1(string):=201071.=20?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=9A=84=E6=9C=80=E5=A4=A7=E5=85=AC?= =?UTF-8?q?=E5=9B=A0=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 31 ++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 4ad6af38d..9272462f0 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2708,4 +2708,33 @@ class Solution: # print(i, j) # 处理特殊情况:[1,-1,1,-1] return res and j - i > 1 -``` \ No newline at end of file +``` + +## 1071. 字符串的最大公因子 + +[原题链接](https://leetcode-cn.com/problems/greatest-common-divisor-of-strings/) + +### 暴力枚举 + +最大公因子必定是 `str1` 或 `str2` 的前缀,因此枚举前缀的长度并截取前缀进行匹配即可。 + +```python +class Solution: + def gcdOfStrings(self, str1: str, str2: str) -> str: + length1 = len(str1) + length2 = len(str2) + for i in range(min(length1, length2), 0, -1): + # 枚举 + if length1 % i == 0 and length2 % i == 0: + # 是否可构成前缀 + if str1[:i] * (length1 // i) == str1 and str1[:i] * (length2 // i) == str2: + return str1[:i] + return '' +``` + +- 时间复杂度: +- 空间复杂度: + +### 数学法 + +若存在 `X`,那么有 `str1 + str2 = str2 + str1`。 \ No newline at end of file From 15bfcc4ec429984e45b6832805f2891845ec6e1c Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 13 Mar 2020 22:03:33 +0800 Subject: [PATCH 067/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20235.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=E7=9A=84=E6=9C=80=E8=BF=91?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E7=A5=96=E5=85=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 49 ++++++++++++++++++++ docs/offer/README.md | 6 ++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 3695284f9..a4d1a5b1b 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -548,6 +548,55 @@ class Solution(object): return root ``` +## 235. 二叉搜索树的最近公共祖先 + +[原题链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) + +### 解一:递归 + +分为几种情况: + +1. `p` 与 `q` 分列 `root` 节点两个子树,则直接返回 `root` +2. `p` 与 `q` 其中之一等于 `root`,则直接返回 `root` +3. 如果 `p` 和 `q` 都在 `root` 左子树,则递归左子树 +4. 如果 `p` 和 `q` 都在 `root` 右子树,则递归右子树 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + if root is None: + return root + # 当前节点为 p 或 q + if p.val == root.val or q.val == root.val: + return root + # 两个节点分别在左右两个子树 + if (p.val < root.val and q.val > root.val) or (p.val > root.val and q.val < root.val): + return root + # 两个节点都在左子树 + if p.val < root.val and q.val < root.val: + return self.lowestCommonAncestor(root.left, p, q) + # 两个节点都在右子树 + if p.val > root.val and q.val > root.val: + return self.lowestCommonAncestor(root.right, p, q) +``` + + + +### 解二:迭代 + +@TODO + ## 236. 二叉树的最近公共祖先 [原题链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/)(同 [面试题68 - II. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/)) diff --git a/docs/offer/README.md b/docs/offer/README.md index 9cbdb843c..3b1a9786b 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -354,4 +354,8 @@ func (this *MaxQueue) Pop_front() int { */ ``` - \ No newline at end of file + + +## 面试题68 - I. 二叉搜索树的最近公共祖先 + +同:235. 二叉搜索树的最近公共祖先 \ No newline at end of file From f6cc0219f4d549031d999a948128dbf55ca3e5a2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 14 Mar 2020 21:45:23 +0800 Subject: [PATCH 068/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20300.=20?= =?UTF-8?q?=E6=9C=80=E9=95=BF=E4=B8=8A=E5=8D=87=E5=AD=90=E5=BA=8F=E5=88=97?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 106 +++++++++++++++++++++---- docs/data-structure/array/README.md | 16 ++-- docs/data-structure/tree/bst/README.md | 102 ++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 21 deletions(-) create mode 100644 docs/data-structure/tree/bst/README.md diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 9a093f3d6..c528b4e0a 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -822,15 +822,11 @@ class Solution(object): 论动态规划,这题和 [322. 零钱兑换](https://leetcode-cn.com/problems/coin-change/) 思路挺像的。 - - ## 300. 最长上升子序列 [原题链接](https://leetcode-cn.com/problems/longest-increasing-subsequence/) -### 思路 - -动态规划。 +### 解一:动态规划 设到某位置 n 的最长上升子序列为 `f(n)`,那么有: @@ -838,27 +834,105 @@ class Solution(object): f(n) = max(f(n), f(x) + 1) (nums[n] > numx[x] and n > x) ``` + + +#### **Python** + ```python -class Solution(object): - def lengthOfLIS(self, nums): - """ - :type nums: List[int] - :rtype: int - """ +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: length = len(nums) if length == 0: return 0 - dp = [1 for _ in range(length)] - - for i in range(1, length): + for i in range(length): for j in range(i): - if nums[i] > nums[j]: + if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1) - return max(dp) ``` +#### **Go** + +```go +func lengthOfLIS(nums []int) int { + length := len(nums) + // 初始化 + dp := make([]int, length) + for i := 0; i < length; i++ { + dp[i] = 1 + } + + for i := 0; i < length; i++ { + for j := 0; j < i; j++ { + if nums[j] < nums[i] { + // dp + if dp[j] + 1 > dp[i] { + dp[i] = dp[j] + 1 + } + } + } + } + + // 返回最大 dp + res := 0 + for i := 0; i < length; i++ { + if dp[i] > res { + res = dp[i] + } + } + + return res +} +``` + + + +- 时间复杂度:$O(n^2)$ +- 空间复杂度:$O(n)$ + +### 解二:贪心 + 二分 + +- 贪心:尾部元素尽可能小才更「有机会上升」 +- 二分:使用二分查找找到要更新的元素 + +使用一个辅助列表 `tails`,用 `tails[i]` 表示长度为 `i` 的上升队列尾部最小元素,`tails` 为递增序列。 + +那么: + +- 如果 `num > tails[-1]`,直接追加 `num` 到 `tails` 尾部,且上升序列长度加 1 +- 否则在 `tails` 使用二分查找,找到第一个比 `num` 小的元素 `tails[k]`,并更新 `tails[k + 1] = num` + +```python +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + # 当前长度 + res = 0 + length = len(nums) + # tails[i] 代表上升子序列长度为 i 时尾部数字 + tails = [] + for num in nums: + if len(tails) == 0 or num > tails[-1]: + # 如果 tails 为空,或 num 大于 tails 最后一位数,追加 num + tails.append(num) + else: + # 使用二分查找,找到第一个比 num 小的数 + left = 0 + right = len(tails) - 1 + loc = right + while left <= right: + mid = (left + right) // 2 + if tails[mid] >= num: + # 找左区间 + loc = mid + right = mid - 1 + else: + # 找右区间 + left = mid + 1 + tails[loc] = num + return len(tails) +``` + ## 309. 最佳买卖股票时机含冷冻期 [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 9272462f0..f08c66c62 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1121,13 +1121,11 @@ class Solution(object): return [i + 1, j + 1] ``` - - -## 169. 求众数 +## 169. 多数元素 [原题链接](https://leetcode-cn.com/problems/majority-element/) -### 解法一 +### 解法一:哈希表 计算每个数出现的个数,使用了额外空间。 @@ -1152,7 +1150,7 @@ class Solution(object): return n ``` -### 解法二 +### 解法二:摩尔投票法 摩尔投票法,相互抵消。 @@ -1180,6 +1178,14 @@ class Solution(object): return major ``` +### 解法三:分治 + +@TODO + +### 解法四:排序 + +@TODO + ## 189. 旋转数组 diff --git a/docs/data-structure/tree/bst/README.md b/docs/data-structure/tree/bst/README.md new file mode 100644 index 000000000..367c0942f --- /dev/null +++ b/docs/data-structure/tree/bst/README.md @@ -0,0 +1,102 @@ +## 220. 存在重复元素 III + +[原题链接](https://leetcode-cn.com/problems/contains-duplicate-iii/) + +### 思路 + +这道题的中文翻译真的很迷,先对题目再做一个翻译: + +给定一个整数数组,判断数组中是否有两个不同的索引 `i` 和 `j`,使得:存在 `abs(i - j) <= k` 时,有 `abs(nums[i] - nums[j]) <=t`。 + +### 解一:暴力破解(超时) + +取出元素 `nums[i]`,在 `i + 1 ~ i + k` 的范围内遍历是否存在 `abs(nums[i] - nums[j]) <= t` 的数,如果存在则返回 `True`。 + +```python +class Solution: + def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool: + num_length = len(nums) + for i in range(num_length): + for j in range(i + 1, i + k + 1): + if j < num_length: + if abs(nums[i] - nums[j]) <= t: + return True + return False +``` + +### 解二:桶 + +使用 `nums[i] // (t + 1)` 计算桶编号,这样保证同一个桶中的元素差值不会超过 `t`,因此只要命中同一个桶即可返回 `True`。 + +因此题需要维护长度为 `k` 的滑动窗口,因此当元素大于 `K` 时需要清理桶中元素。 + +```python +class Solution: + def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool: + if t < 0: + return False + bucket = dict() + for i in range(len(nums)): + bucket_num = nums[i] // (t + 1) + if bucket_num in bucket: + # 命中 + return True + # 检查前后两个桶,因为范围是 2t + if bucket_num + 1 in bucket and abs(bucket[bucket_num + 1] - nums[i]) <= t: + return True + if bucket_num - 1 in bucket and abs(bucket[bucket_num - 1] - nums[i]) <= t: + return True + bucket[bucket_num] = nums[i] + if len(bucket) > k: + # 弹出元素 + bucket.pop(nums[i - k] // (t + 1)) + return False +``` + +```go +func containsNearbyAlmostDuplicate(nums []int, k int, t int) bool { + // var bucket map[int]int + if t < 0 { + return false + } + var bucket = make(map[int]int) + for i := 0; i < len(nums); i++ { + // 计算桶编号 + bucketNum := getBucketKey(nums[i], t + 1) + // 是否命中桶 + if _, ok := bucket[bucketNum]; ok { + // 存在 + return true + } + // 是否命中相邻桶 + if val, ok := bucket[bucketNum - 1]; ok { + if val - nums[i] <= t && val - nums[i] >= -t { + return true + } + } + if val, ok := bucket[bucketNum + 1]; ok { + if val - nums[i] <= t && val - nums[i] >= -t { + return true + } + } + bucket[bucketNum] = nums[i] + // 多余元素弹出 + if len(bucket) > k { + delete(bucket, getBucketKey(nums[i - k], t + 1)) + } + } + return false +} + +func getBucketKey(num int, t int) int { + if num < 0 { + return (num + 1) / (t - 1) + } else { + return num / t + } +} +``` + +### 解三:平衡二叉树 + + From 28d63168a36abf7a9f1e2c28b14919935b604875 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 15 Mar 2020 20:07:18 +0800 Subject: [PATCH 069/181] =?UTF-8?q?=F0=9F=90=B1(dfs):=20695.=20=E5=B2=9B?= =?UTF-8?q?=E5=B1=BF=E7=9A=84=E6=9C=80=E5=A4=A7=E9=9D=A2=E7=A7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/research/dfs/README.md | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/algorithm/research/dfs/README.md b/docs/algorithm/research/dfs/README.md index d5ec77434..c0d943132 100644 --- a/docs/algorithm/research/dfs/README.md +++ b/docs/algorithm/research/dfs/README.md @@ -117,4 +117,41 @@ class Solution(object): return for i in xrange(index, len(nums)): self.dfs(target - nums[i], i + 1, tmp_list + [nums[i]], res, nums) +``` + +## 695. 岛屿的最大面积 + +[原题链接](https://leetcode-cn.com/problems/max-area-of-island/) + +### 深度优先搜索 + +设计一个递归函数:输入坐标 `(i, j)`,返回该位置能构成岛屿的最大面积。 + +- 如果该位置不是岛屿,返回 0 +- 如果该位置是岛屿,计算其上下左右位置的面积并相加(此过程不断递归) + +```python +class Solution: + def maxAreaOfIsland(self, grid: List[List[int]]) -> int: + res = 0 + for i in range(len(grid)): + for j in range(len(grid[0])): + res = max(self.dfs(grid, i, j), res) + return res + + def dfs(self, grid, i, j): + """ + 返回面积 + """ + if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]) or grid[i][j] != 1: + return 0 + # 避免重复计算 + grid[i][j] = 0 + # 是岛屿,面积为 1 + ans = 1 + # 四个方向 + for di, dj in [[0, -1], [0, 1], [-1, 0], [1, 0]]: + # 计算四个方向总面积 + ans += self.dfs(grid, i + di, j + dj) + return ans ``` \ No newline at end of file From 40cb448b54decbbd3b7562633faafae5db31ba05 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 16 Mar 2020 13:20:57 +0800 Subject: [PATCH 070/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2001.06.=20=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index 3b1a9786b..b5385a2e1 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -1,3 +1,68 @@ +## 面试题 01.06. 字符串压缩 + +[原题链接](https://leetcode-cn.com/problems/compress-string-lcci/) + +### 思路 + + + +#### **Python** + +```python +class Solution: + def compressString(self, S: str) -> str: + s_length = len(S) + if s_length == 0: + return S + res = '' + cur = '' + count = 0 + for s in S: + if s != cur: + if cur != '': + res += cur + str(count) + cur = s + count = 1 + else: + count += 1 + # 尾部处理 + res += cur + str(count) + return res if len(res) < s_length else S +``` + +#### **Go** + +```go +func compressString(S string) string { + sLength := len(S) + if sLength == 0 { + return S + } + var res string + var cur rune + var empty rune + var count int + for _, s := range S { + if s != cur { + if cur != empty { + res += string(cur) + strconv.Itoa(count) + } + cur = s + count = 1 + } else { + count += 1 + } + } + res += string(cur) + strconv.Itoa(count) + if len(res) < sLength { + return res + } + return S +} +``` + + + ## 面试题03. 数组中重复的数字 [原题链接](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/) From 2668785d4953923124ee9901b07b19689827b536 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 16 Mar 2020 13:22:19 +0800 Subject: [PATCH 071/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2001.06.=20=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 golang 知识点 --- docs/offer/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index b5385a2e1..0f6756d99 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -32,6 +32,11 @@ class Solution: #### **Go** +Go 字符串相关知识点: + +- `rune` -> `string`:`string(rune)` +- `int` -> `string`: `strconv.Itoa(int)` + ```go func compressString(S string) string { sLength := len(S) From ece29c75fb49d5bef59a50aaffad782f26e20373 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 16 Mar 2020 20:52:28 +0800 Subject: [PATCH 072/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20110.=20=E5=B9=B3?= =?UTF-8?q?=E8=A1=A1=E4=BA=8C=E5=8F=89=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 补充自顶向下解法 2. 补充 golang 题解 --- docs/data-structure/tree/recursion/README.md | 130 ++++++++++++++++--- 1 file changed, 109 insertions(+), 21 deletions(-) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index a4d1a5b1b..f30b1d1fe 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -364,35 +364,123 @@ func findIndex(array []int, num int) int { [原题链接](https://leetcode-cn.com/problems/balanced-binary-tree/description/) -### 思路 - 和 [104](/tree/104.md) 的套路一样,加上对比逻辑而已。 +### 解一:自顶向下 + +对每个节点都计算它左右子树的高度,判断是否为平衡二叉树。 + ```python -class Solution(object): - - result = True - - def isBalanced(self, root): +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def isBalanced(self, root: TreeNode) -> bool: + if root is None: + return True + left_depth = self.helper(root.left, 0) + right_depth = self.helper(root.right, 0) + if abs(left_depth - right_depth) > 1: + # 不平衡 + return False + return self.isBalanced(root.left) and self.isBalanced(root.right) + + def helper(self, root, depth): """ - :type root: TreeNode - :rtype: bool + 返回节点高度 """ - self.depth(root) - return self.result - - def depth(self, root): if root is None: - return 0 - else: - left_depth = self.depth(root.left) - right_depth = self.depth(root.right) - if (abs(left_depth - right_depth) > 1): - self.result = False - - return max(left_depth, right_depth) + 1 + return depth + left_depth = self.helper(root.left, depth + 1) + right_depth = self.helper(root.right, depth + 1) + return max(left_depth, right_depth) ``` +- 时间复杂度:$O(nlogn)$。最差情况需要遍历树的所有节点,判断每个节点的最大高度又需要遍历该节点的所有子节点。详见[题解中的复杂度分析](https://leetcode-cn.com/problems/balanced-binary-tree/solution/ping-heng-er-cha-shu-by-leetcode/)。 +- 空间复杂度:$O(n)$。如果树完全倾斜(退化成链),递归栈将包含所有节点。 + +### 解二:自底向上 + +自顶向下的高度计算存在大量冗余,每次计算高度时,同时都要计算子树的高度。 + +从底自顶返回二叉树高度,如果某子树不是平衡树,提前进行枝剪。 + + + +#### **Python** + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + res = True + def isBalanced(self, root: TreeNode) -> bool: + self.helper(root, 0) + return self.res + + def helper(self, root, depth): + if root is None: + return depth + left_depth = self.helper(root.left, depth + 1) + right_depth = self.helper(root.right, depth + 1) + if abs(left_depth - right_depth) > 1: + self.res = False + # 提前返回 + return 0 + return max(left_depth, right_depth) +``` + +- 时间复杂度:$O(n)$。n 为树的节点数,最坏情况需要遍历所有节点。 +- 空间复杂度:$O(n)$。完全不平衡时需要的栈空间。 + +#### **Go** + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +var res bool + +func isBalanced(root *TreeNode) bool { + res = true + helper(root, 0) + return res +} + +func helper(root *TreeNode, depth int) int { + if root == nil { + return depth + } + leftDepth := helper(root.Left, depth + 1) + rightDepth := helper(root.Right, depth + 1) + if leftDepth - rightDepth > 1 || leftDepth - rightDepth < -1 { + res = false + return 0 + } + if leftDepth > rightDepth { + return leftDepth + } else { + return rightDepth + } +} +``` + + + ## 111. 二叉树的最小深度 From 5548ff8caf24208ad23f7198302bcb6ee012dbfc Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 16 Mar 2020 21:09:47 +0800 Subject: [PATCH 073/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20110.=20=E5=B9=B3?= =?UTF-8?q?=E8=A1=A1=E4=BA=8C=E5=8F=89=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充复杂度说明 --- docs/data-structure/tree/recursion/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index f30b1d1fe..6a60928d8 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -400,7 +400,7 @@ class Solution: return max(left_depth, right_depth) ``` -- 时间复杂度:$O(nlogn)$。最差情况需要遍历树的所有节点,判断每个节点的最大高度又需要遍历该节点的所有子节点。详见[题解中的复杂度分析](https://leetcode-cn.com/problems/balanced-binary-tree/solution/ping-heng-er-cha-shu-by-leetcode/)。 +- 时间复杂度:$O(nlogn)$。最差情况需要遍历树的所有节点,判断每个节点的最大高度又需要遍历该节点的所有子节点。如果树是倾斜的,则会到达 $O(n^2)$ 复杂度。详见[题解中的复杂度分析](https://leetcode-cn.com/problems/balanced-binary-tree/solution/ping-heng-er-cha-shu-by-leetcode/)。 - 空间复杂度:$O(n)$。如果树完全倾斜(退化成链),递归栈将包含所有节点。 ### 解二:自底向上 From 5ea5a8823017d2834c55a8c837ec9f89590f863d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 17 Mar 2020 20:17:13 +0800 Subject: [PATCH 074/181] =?UTF-8?q?=F0=9F=90=B1(hash):=201160.=20=E6=8B=BC?= =?UTF-8?q?=E5=86=99=E5=8D=95=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 94 +++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 7b57c7c4c..839cc097d 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -490,4 +490,96 @@ class MyHashSet: # param_3 = obj.contains(key) ``` -### 解二:链表模拟 \ No newline at end of file +### 解二:链表模拟 + +## 1160. 拼写单词 + +[原题链接](https://leetcode-cn.com/problems/find-words-that-can-be-formed-by-characters/) + +### 思路 + +使用哈希表存储 `chars` 中每个字符出现的次数,在遍历 `words` 时判断每个单词的字母是否可以命中 `chars` 的哈希表。 + + + +#### **Python** + +```python +class Solution: + def countCharacters(self, words: List[str], chars: str) -> int: + res = 0 + word_dict = dict() + # 词汇统计 + for c in chars: + if c not in word_dict: + word_dict[c] = 0 + word_dict[c] += 1 + + # 开始拼写 + for word in words: + tmp_word_dict = word_dict.copy() + get = True + for c in word: + if c in tmp_word_dict: + if tmp_word_dict[c] == 0: + get = False + break + else: + tmp_word_dict[c] -= 1 + else: + get = False + break + if get: + res += len(word) + + return res +``` + +#### **Go** + +```go +func countCharacters(words []string, chars string) int { + var res int + var wordMap = make(map[string]int) + // 统计 chars + for _, c := range chars { + if _, ok := wordMap[string(c)]; !ok { + // 不存在 + wordMap[string(c)] = 0 + } + wordMap[string(c)] += 1 + } + + // 统计 word 单词数,与统计比较 + for _, word := range words { + everyWordMap := make(map[string]int) + for _, c := range word { + if _, ok := everyWordMap[string(c)]; !ok { + everyWordMap[string(c)] = 0 + } + everyWordMap[string(c)] += 1 + } + + // 判断是否命中 + get := true + for c, count := range everyWordMap { + if mapCount, ok := wordMap[string(c)]; ok { + // 存在 + if count > mapCount { + get = false + break + } + } else { + get = false + break + } + } + if get { + res += len(word) + } + } + return res +} +``` + + \ No newline at end of file From bf11a1ee251c895c9763ba4da8cc4b7a9e7045f8 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 18 Mar 2020 21:15:36 +0800 Subject: [PATCH 075/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20589.=20N=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E5=89=8D=E5=BA=8F=E9=81=8D=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/n-ary/README.md | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 docs/data-structure/tree/n-ary/README.md diff --git a/docs/data-structure/tree/n-ary/README.md b/docs/data-structure/tree/n-ary/README.md new file mode 100644 index 000000000..8d8aa467a --- /dev/null +++ b/docs/data-structure/tree/n-ary/README.md @@ -0,0 +1,62 @@ +## 589. N叉树的前序遍历 + +[原题链接](https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/) + +### 解一:递归 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def preorder(self, root: 'Node') -> List[int]: + res = [] + self.helper(root, res) + return res + + def helper(self, root, res): + if root is None: + return + res.append(root.val) + children = root.children + for child in children: + self.helper(child, res) +``` + +### 解二:遍历 + +用栈辅助。 + +1. 首先,将 `root` 压入栈中 +2. 在栈不为空时,对栈进行遍历,每次弹出栈顶元素 +3. 若栈顶元素节点不为空,则将该节点值放入结果集中,且将该节点的子节点**从右至左**压入栈中(这样弹出时就是从左至右,符合前序遍历的顺序) + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def preorder(self, root: 'Node') -> List[int]: + stack = [] + stack.append(root) + res = [] + while len(stack) > 0: + top = stack.pop() + if top is None: + continue + res.append(top.val) + # 反序插入子节点 + children = top.children + for i in range(len(children) - 1, -1, -1): + child = children[i] + stack.append(child) + return res +``` \ No newline at end of file From 8b51bdb5ab904ad78b1f627f52e7c049319d837c Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 18 Mar 2020 21:45:43 +0800 Subject: [PATCH 076/181] =?UTF-8?q?=F0=9F=90=B1(math):=20836.=20=E7=9F=A9?= =?UTF-8?q?=E5=BD=A2=E9=87=8D=E5=8F=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/math/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/algorithm/math/README.md b/docs/algorithm/math/README.md index 1bebec5bc..6ad5a6a32 100644 --- a/docs/algorithm/math/README.md +++ b/docs/algorithm/math/README.md @@ -484,6 +484,27 @@ class Solution: return "x=" + str(-num // x_count) ``` +## 836. 矩形重叠 + +[原题链接](https://leetcode-cn.com/problems/rectangle-overlap/) + +### 思路 + +判断「不相交」的条件。 + +```python +class Solution: + def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: + ax1, ay1 = rec1[0], rec1[1] + ax2, ay2 = rec1[2], rec1[3] + bx1, by1 = rec2[0], rec2[1] + bx2, by2 = rec2[2], rec2[3] + # 判断是否相交 + if ax2 <= bx1 or ax1 >= bx2 or ay2 <= by1 or ay1 >= by2: + return False + return True +``` + ## 1103. 分糖果 II [原题链接](https://leetcode-cn.com/problems/distribute-candies-to-people/) From 70e8bba581a132ecc904ff713b444b351f324f4a Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 18 Mar 2020 21:48:28 +0800 Subject: [PATCH 077/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20836.=20=E7=9F=A9?= =?UTF-8?q?=E5=BD=A2=E9=87=8D=E5=8F=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 golang 解法 --- docs/algorithm/math/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/algorithm/math/README.md b/docs/algorithm/math/README.md index 6ad5a6a32..870508287 100644 --- a/docs/algorithm/math/README.md +++ b/docs/algorithm/math/README.md @@ -492,6 +492,10 @@ class Solution: 判断「不相交」的条件。 + + +#### **Python** + ```python class Solution: def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: @@ -505,6 +509,23 @@ class Solution: return True ``` +#### **Go** + +```go +func isRectangleOverlap(rec1 []int, rec2 []int) bool { + ax1, ay1 := rec1[0], rec1[1] + ax2, ay2 := rec1[2], rec1[3] + bx1, by1 := rec2[0], rec2[1] + bx2, by2 := rec2[2], rec2[3] + if ax2 <= bx1 || ax1 >= bx2 || ay2 <= by1 || ay1 >= by2 { + return false + } + return true +} +``` + + + ## 1103. 分糖果 II [原题链接](https://leetcode-cn.com/problems/distribute-candies-to-people/) From 0ac2a2361324f9bc720656daba01248546a804e0 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 19 Mar 2020 19:35:55 +0800 Subject: [PATCH 078/181] =?UTF-8?q?=F0=9F=90=B1(n-ary):=20590.=20N?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=90=8E=E5=BA=8F=E9=81=8D=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/n-ary/README.md | 58 ++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/data-structure/tree/n-ary/README.md b/docs/data-structure/tree/n-ary/README.md index 8d8aa467a..c56bfcdeb 100644 --- a/docs/data-structure/tree/n-ary/README.md +++ b/docs/data-structure/tree/n-ary/README.md @@ -59,4 +59,62 @@ class Solution: child = children[i] stack.append(child) return res +``` + +## 590. N叉树的后序遍历 + +[原题链接](https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/) + +### 解一:递归 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def postorder(self, root: 'Node') -> List[int]: + res = [] + self.healper(root, res) + return res + + def healper(self, root, res): + if root is None: + return + children = root.children + for child in children: + self.healper(child, res) + res.append(root.val) +``` + +### 解二:迭代 + +用一个辅助栈。 + +后序遍历的顺序是:子节点从左至右 -> 根节点。因此我们可以先把「根节点 -> 子节点从右至左」写入结果集中,在返回时再将结果集反序。 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def postorder(self, root: 'Node') -> List[int]: + res = [] + stack = [] + stack.append(root) + while len(stack): + top = stack.pop() + if top is None: + continue + res.append(top.val) + for child in top.children: + stack.append(child) + return res[::-1] ``` \ No newline at end of file From 574c350829aef4cc5a6c13fe75fc98ce02d6287b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 19 Mar 2020 20:03:01 +0800 Subject: [PATCH 079/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20409.=20=E6=9C=80?= =?UTF-8?q?=E9=95=BF=E5=9B=9E=E6=96=87=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 golang 题解 + 二刷 --- docs/data-structure/string/README.md | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/data-structure/string/README.md b/docs/data-structure/string/README.md index 0f80b77e7..a5f3aba12 100644 --- a/docs/data-structure/string/README.md +++ b/docs/data-structure/string/README.md @@ -1246,6 +1246,68 @@ class Solution(object): return length + num ``` +---- + +2020.03.19 二刷 + +在最后返回时可以判断下结果长度和最初字符串的长度,如果结果长度短,则将结果长度 +1(即加上任何一个字符构成奇数回文串)。 + + + +#### **Python** + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + length = len(s) + c_map = dict() + for c in s: + if c not in c_map: + c_map[c] = 0 + c_map[c] += 1 + res = 0 + for v in c_map.values(): + if v % 2 == 0: + # 偶数处理 + res += v + else: + # 奇数处理 + res += (v - 1) + return res + 1 if res < length else res +``` + +#### **Go** + +```go +func longestPalindrome(s string) int { + res := 0 + cMap := make(map[string]int) + // 数据统计 + for _, c := range s { + if _, ok := cMap[string(c)]; !ok { + cMap[string(c)] = 0 + } + cMap[string(c)] += 1 + } + + // 判断奇偶 + for _, value := range cMap { + if value % 2 == 0 { + res += value + } else { + res += (value - 1) + } + } + + if res < len(s) { + return res + 1 + } + return res +} +``` + + + ## 459. 重复的子字符串 From 1892eb97cfad568a8b01f241658dd8187115d17d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 20 Mar 2020 16:53:23 +0800 Subject: [PATCH 080/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20429.=20N=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E5=B1=82=E5=BA=8F=E9=81=8D=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/n-ary/README.md | 69 ++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/docs/data-structure/tree/n-ary/README.md b/docs/data-structure/tree/n-ary/README.md index c56bfcdeb..92345f2bb 100644 --- a/docs/data-structure/tree/n-ary/README.md +++ b/docs/data-structure/tree/n-ary/README.md @@ -1,3 +1,72 @@ +## 429. N叉树的层序遍历 + +[原题链接](https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/) + +### 解一:迭代 + +用队列辅助。 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + queue = [] + res = [] + queue.append(root) + while len(queue) > 0: + q_length = len(queue) + tmp = [] + for i in range(q_length): + first = queue[0] + del queue[0] + if first is None: + continue + tmp.append(first.val) + for child in first.children: + queue.append(child) + if len(tmp) > 0: + res.append(tmp) + return res +``` + +- 时间复杂度:$O(n)$,n 为节点数量 +- 空间复杂度:$O(n)$ + +### 解二:递归 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + res = [] + self.helper(res, root, 0) + return res + + def helper(self, res, root, level): + if root is None: + return + if len(res) == level: + res.append([]) + res[level].append(root.val) + for child in root.children: + self.helper(res, child, level + 1) +``` + +- 时间复杂度:$O(n)$ +- 空间复杂度:最坏 $O(n)$,最好 $O(logn)$ + ## 589. N叉树的前序遍历 [原题链接](https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/) From 0e156b36bbe72f0f5a2c0676a274706a01f25abf Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 21 Mar 2020 13:12:05 +0800 Subject: [PATCH 081/181] =?UTF-8?q?=F0=9F=90=B1(research):=20365.=20?= =?UTF-8?q?=E6=B0=B4=E5=A3=B6=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/research/dfs/README.md | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/algorithm/research/dfs/README.md b/docs/algorithm/research/dfs/README.md index c0d943132..7f8bfccff 100644 --- a/docs/algorithm/research/dfs/README.md +++ b/docs/algorithm/research/dfs/README.md @@ -119,6 +119,54 @@ class Solution(object): self.dfs(target - nums[i], i + 1, tmp_list + [nums[i]], res, nums) ``` +## 365. 水壶问题 + +[原题链接](https://leetcode-cn.com/problems/water-and-jug-problem/) + +### 解一:深度优先搜索 + +列举每次倒水的几种情况: + +1. 把 x 倒空 +2. 把 x 倒满 +3. 把 y 倒空 +4. 把 y 倒满 +5. 把 x 倒入 y,直到 y 满或 x 空 +6. 把 y 倒入 x,直到 x 满或 y 空 + +因为 Python 中会超过最大递归次数,所以用栈模拟递归过程。 + +```python +class Solution: + def canMeasureWater(self, x: int, y: int, z: int) -> bool: + # (x 剩余,y 剩余) + stack = [(0, 0)] + # 标记重复 + mark = set() + while len(stack) > 0: + remain_x, remain_y = stack.pop() + if remain_x == z or remain_y == z or remain_x + remain_y == z: + return True + # 是否已标记过该情况 + if (remain_x, remain_y) in mark: + continue + mark.add((remain_x, remain_y)) + # 分情况讨论 + # 倒满 x + stack.append((x, remain_y)) + # 倒满 y + stack.append((remain_x, y)) + # 清空 x + stack.append((0, remain_y)) + # 清空 y + stack.append((remain_x, 0)) + # 把 x 倒进 y,直到 y 满或 x 空 + stack.append((remain_x - min(remain_x, y - remain_y), remain_y + min(remain_x, y - remain_y))) + # 把 y 倒进 x,直到 x 满或 y 空 + stack.append((remain_x + min(remain_y, x - remain_x), remain_y - min(remain_y, x - remain_x))) + return False +``` + ## 695. 岛屿的最大面积 [原题链接](https://leetcode-cn.com/problems/max-area-of-island/) From aab4c32022a5fa33def5110917c480217b706c83 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 22 Mar 2020 00:02:16 +0800 Subject: [PATCH 082/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20559.=20N=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/n-ary/README.md | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/data-structure/tree/n-ary/README.md b/docs/data-structure/tree/n-ary/README.md index 92345f2bb..3194e3012 100644 --- a/docs/data-structure/tree/n-ary/README.md +++ b/docs/data-structure/tree/n-ary/README.md @@ -67,6 +67,32 @@ class Solution: - 时间复杂度:$O(n)$ - 空间复杂度:最坏 $O(n)$,最好 $O(logn)$ +## 559. N叉树的最大深度 + +[原题链接](https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/) + +### 递归 + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" +class Solution: + def maxDepth(self, root: 'Node') -> int: + if root is None: + return 0 + if len(root.children) == 0: + return 1 + max_depth = 0 + for child in root.children: + max_depth = max(max_depth, self.maxDepth(child)) + return max_depth + 1 +``` + ## 589. N叉树的前序遍历 [原题链接](https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/) From 204f0912fb135f0e3d45efe7fac3d93815d918a9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 24 Mar 2020 22:32:51 +0800 Subject: [PATCH 083/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2017.16.=20=E6=8C=89=E6=91=A9=E5=B8=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 43 +++++++++++++++++++++++++++++ docs/offer/README.md | 27 ++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index f08c66c62..63e7d1aaf 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2630,6 +2630,49 @@ func getMin(a int, b int) int { } ``` +## 945. 使数组唯一的最小增量 + +[原题链接](https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique/) + +### 解一:计数 + +一开始暴力破解超时了,优化一下采用以下写法: + +1. 先把重复出现的数字存储起来 +2. 遍历 0~80000 的数字(最坏情况出现 40000 个 40000,最多可以叠加到 80000) + - 如果发现数字是重复出现过的: + - 将记录重复出现数字的 `repeat` 变量 + 1 + - 在结果 `res` 提前减去 `重复个数 * 重复数字` + - 如果发现是空的位置: + - 用空的位置处理一个重复出现的数字:`repeat -= 1` + - 在 `res` 加上空位的数字 + +```python +class Solution: + def minIncrementForUnique(self, A: List[int]) -> int: + count = [0 for _ in range(80000)] + for x in A: + count[x] += 1 + + # 总数 + res = 0 + # 重复数量 + repeat = 0 + + for i in range(80000): + if count[i] > 1: + # 出现重复 + repeat += count[i] - 1 + # 减去多余的数 + res -= i * (count[i] - 1) + # 没有出现过的数 + if count[i] == 0 and repeat > 0: + repeat -= 1 # 处理一个重复的数 + res += i + + return res +``` + ## 1002. 查找常用字符 diff --git a/docs/offer/README.md b/docs/offer/README.md index 0f6756d99..2c9c0acfd 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -247,6 +247,33 @@ func reversePrint(head *ListNode) []int { - 时间复杂度:$O(n)$ - 空间复杂度:$O(n)$ +## 面试题 17.16. 按摩师 + +[原题链接](https://leetcode-cn.com/problems/the-masseuse-lcci/) + +### 动态规划 + +- 用 `dp[0][i]` 表示不接 i 预约可以获得的最长预约时间 +- 用 `dp[1][i]` 表示接 i 预约可以获得的最长预约时间 + +```python +class Solution: + def massage(self, nums: List[int]) -> int: + # dp[0][i] 不接 + # dp[1][i] 接 + length = len(nums) + if length == 0: + return 0 + dp = [[0 for _ in range(length)] for _ in range(2)] + # 转移方程:dp[0][i] = max(dp[1][i - 1], dp[0][i - 1]) + # dp[1][i] = max(dp[0][i - 1] + nums[i]) + dp[1][0] = nums[0] + for i in range(1, length): + dp[0][i] = max(dp[1][i - 1], dp[0][i - 1]) + dp[1][i] = dp[0][i - 1] + nums[i] + return max(dp[0][length - 1], dp[1][length - 1]) +``` + ## 面试题24. 反转链表 [原题链接](https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/) From b937b6a17b7f8f4a6d60fa6dea62410d4baf64ee Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 26 Mar 2020 16:02:06 +0800 Subject: [PATCH 084/181] =?UTF-8?q?=F0=9F=90=B1(array):=20999.=20=E8=BD=A6?= =?UTF-8?q?=E7=9A=84=E5=8F=AF=E7=94=A8=E6=8D=95=E8=8E=B7=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 55 +++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 63e7d1aaf..b832375cf 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2673,6 +2673,61 @@ class Solution: return res ``` +## 999. 车的可用捕获量 + +[原题链接](https://leetcode-cn.com/problems/available-captures-for-rook/) + +### 思路 + +找车的四个方向是否能直接碰到卒。 + +```python +class Solution: + def numRookCaptures(self, board: List[List[str]]) -> int: + # 找到车的位置(R) + m = len(board) + if m == 0: + return 0 + n = len(board[0]) + r_x, r_y = -1, -1 + for i in range(m): + for j in range(n): + if board[i][j] == 'R': + r_x, r_y = i, j + break + res = 0 + # 找左侧 + for j in range(r_y - 1, -1, -1): + if board[r_x][j] == 'B': + break + if board[r_x][j] == 'p': + res += 1 + break + # 找右侧 + for j in range(r_y + 1, n): + if board[r_x][j] == 'B': + break + if board[r_x][j] == 'p': + res += 1 + break + # 找上侧 + for i in range(r_x - 1, -1, -1): + if board[i][r_y] == 'B': + break + if board[i][r_y] == 'p': + res += 1 + break + # 找下侧 + for i in range(r_x + 1, m): + if board[i][r_y] == 'B': + break + if board[i][r_y] == 'p': + res += 1 + break + + return res +``` + ## 1002. 查找常用字符 From 923ea98a251a5aad9042cd5d2abefb517357cfc3 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 27 Mar 2020 21:39:28 +0800 Subject: [PATCH 085/181] =?UTF-8?q?=F0=9F=90=B1(array):=20914.=20=E5=8D=A1?= =?UTF-8?q?=E7=89=8C=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index b832375cf..45abd41aa 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2630,6 +2630,52 @@ func getMin(a int, b int) int { } ``` +## 914. 卡牌分组 + +[原题链接](https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/) + +### 解一:暴力枚举 + +```python +class Solution: + def hasGroupsSizeX(self, deck: List[int]) -> bool: + if len(deck) == 0: + return False + min_num = 10000 + max_num = 0 + num_map = dict() + for d in deck: + if d not in num_map: + num_map[d] = 0 + num_map[d] += 1 + + for num_count in num_map.values(): + min_num = min(min_num, num_count) + max_num = max(max_num, num_count) + + if min_num < 2: + return False + + for i in range(2, max_num + 1): + mark = True + for num_count in num_map.values(): + if num_count < i or num_count % i != 0: + mark = False + break + if mark: + return True + return False +``` + +- 时间复杂度:$O(n^2)$ +- 空间复杂度:$O(n)$ + +### 解二:求最大公约数 + +要求的 x 必须是所有卡牌数量的约数。 + +@TODO + ## 945. 使数组唯一的最小增量 [原题链接](https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique/) From 3dd558267c8f86747f418e59875920e58c86a5a2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 28 Mar 2020 16:50:19 +0800 Subject: [PATCH 086/181] =?UTF-8?q?=F0=9F=90=B1(trie):=20820.=20=E5=8D=95?= =?UTF-8?q?=E8=AF=8D=E7=9A=84=E5=8E=8B=E7=BC=A9=E7=BC=96=E7=A0=81=20?= =?UTF-8?q?=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/trie/README.md | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/data-structure/tree/trie/README.md b/docs/data-structure/tree/trie/README.md index a6661ea56..716e3e2a6 100644 --- a/docs/data-structure/tree/trie/README.md +++ b/docs/data-structure/tree/trie/README.md @@ -74,6 +74,34 @@ class Solution: - 时间复杂度:$O(\sum w_{i}^2)$($w_{i}$ 为 `words[i]` 的长度),遍历每个单词 + 截取后缀 - 空间复杂度:$O(\sum w_{i})$,所有后缀存储的空间开销 +2020.03.28 复盘: + +```python +class Solution: + def minimumLengthEncoding(self, words: List[str]) -> int: + if len(words) == 1: + return len(words[0]) + 1 + # 单词整合 + # 结果:剩余单词长度 + 剩余单词数量(# 数量) + # 倒过来比较 + reverse_words = [word[::-1] for word in words] + # 排序 + reverse_words.sort() + res = 0 + for i in range(1, len(reverse_words)): + pre_word = reverse_words[i - 1] + cur_word = reverse_words[i] + # 双指针 + for j in range(len(pre_word)): + if pre_word[j] != cur_word[j]: + # pre_word 需要单独处理 + res += len(pre_word) + 1 + break + # 需要加上最后一个 cur_word + res += len(cur_word) + 1 + return res +``` + #### **Java** ```java From f07dda6f1d0d24408a528297a0c3afb4fa122f36 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 29 Mar 2020 23:20:59 +0800 Subject: [PATCH 087/181] =?UTF-8?q?=F0=9F=90=B1(bfs):=201162.=20=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/research/bfs/README.md | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/algorithm/research/bfs/README.md b/docs/algorithm/research/bfs/README.md index c10a81c4c..d85b3c36b 100644 --- a/docs/algorithm/research/bfs/README.md +++ b/docs/algorithm/research/bfs/README.md @@ -60,4 +60,60 @@ class Solution(object): grid[node_area_x][node_area_y] = '0' return res +``` + +## 1162. 地图分析 + +[原题链接](https://leetcode-cn.com/problems/as-far-from-land-as-possible/) + +### 解一:广度优先搜索 + +- 先遍历 `grid` 一次,把陆地都存入队列,作为 BFS 第一层 +- 将队列中的陆地元素取出,分别向上下左右走一步,如果遇到了海洋则继续加入队列,作为 BFS 下一层 + - 遇到的海洋标记为 `2` 防止重复遍历 + +这样以来,BFS 走的最大层数就是最后要求的最远距离(将 曼哈顿距离 转为步数处理)。 + +```python +class Solution: + def maxDistance(self, grid: List[List[int]]) -> int: + m = len(grid) + if m == 0: + return -1 + n = len(grid[0]) + queue = [] + for i in range(m): + for j in range(n): + if grid[i][j] == 1: + # 发现陆地,加入队列 + queue.append([i, j]) + + if len(queue) == 0 or len(queue) == m * n: + return -1 + + distance = -1 + while len(queue) > 0: + distance += 1 + length = len(queue) + for i in range(length): + # 取出所有位置 + first = queue[0] + x, y = first[0], first[1] + del queue[0] + # 上下左右四个方向 + if x - 1 >= 0 and grid[x - 1][y] == 0: + # 避免重复判断 + grid[x - 1][y] = 2 + queue.append([x - 1, y]) + if x + 1 < m and grid[x + 1][y] == 0: + grid[x + 1][y] = 2 + queue.append([x + 1, y]) + if y - 1 >= 0 and grid[x][y - 1] == 0: + grid[x][y - 1] = 2 + queue.append([x, y - 1]) + if y + 1 < n and grid[x][y + 1] == 0: + grid[x][y + 1] = 2 + queue.append([x, y + 1]) + + return distance ``` \ No newline at end of file From f77455306523e00c110541579e506b86eb6016fd Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 30 Mar 2020 21:36:42 +0800 Subject: [PATCH 088/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=9862.=20=E5=9C=86=E5=9C=88=E4=B8=AD=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E5=89=A9=E4=B8=8B=E7=9A=84=E6=95=B0=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 85 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index 2c9c0acfd..791ff54d6 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -453,6 +453,91 @@ func (this *MaxQueue) Pop_front() int { +## 面试题62. 圆圈中最后剩下的数字 + +[原题链接](https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/) + +### 思路 + +我们用 `f(n, m)` 表示从 n 个数中每次删除第 m 个数(共删除了 n - 1 次),最后留下的那个数的**序号**。 + +我们从 `f(n, m)` 场景下删除的第 1 个数是从序号 0 开始,向后数 m 个数得到的。删除第一个数后,将剩下 n - 1 个数,此时场景变为 `f(n - 1, m)`,用于表示从 n - 1 个数中每次删除第 m 个数最后留下的数的**序号**。 + +在往下看之前,我们先达成一个共识:**`f(n, m)` 与 `f(n - 1, m)` 得到的数是同一个数(最后剩下的数在每一轮中都不可能被删除),只是在它们所在的场景下,这个数字的序号不同罢了。** + +那么,何谓「所在场景,序号不同」? + +这里所说的「序号」与**所在场景下首次选取删除数字的出发点有关**,我们直接看下题目给出的 `n = 5, m = 3` 这个例子,已知答案为 3。 + +### 不同场景下的不同序号 + +#### f(n, m) 场景 + +此时 `n = 5`,由于我们从第 1 个数字出发,所以从第 1 个数字开始编号: + +``` +数字: +0 1 2 3 4 +序号: +0 1 2 3 4 +``` + +可以看到答案 3 在该场景下的序号为 3。 + +#### f(n - 1, m) 场景 + +此时,我们已经在 `f(n, m)` 场景下删除一个数了,这个数是 2,因此我们要从 3 开始重新编号: + +``` +数字: +0 1 3 4 +序号: +2 3 0 1 +``` + +答案 3 在该场景下的序号为 0。 + +### 两者序号的关系 + +我们知道,从 `f(n - m)` 场景下删除的第一个数的**序号**是 `(m - 1) % n`,那么 `f(n - 1, m)` 场景将使用被删除数字的下一个数,即序号 `m % n` 作为它的 0 序号。 + +设 `f(n - 1, m)` 的结果为 `x`,`x` 是从 `f(n, m)` 场景下序号为 `m % n` 的数字出发所获得的结果,因此,我们可以得出:`m % n + x` 是该数字在 `f (n, m)` 场景下的结果序号。即: + +``` +f(n, m) = m % n + x +``` +但由于 `m % n + x` 可能会超过 n 的范围,所以我们再取一次模: + +``` +f(n , m) = (m % n + x) % n = (m + x) % n +``` + +将 `f(n - 1, m)` 代回,得到递推公式: + +``` +f(n, m) = (m + f(n - 1, m)) % n +``` + +有了递推公式后,想递归就递归,想迭代就迭代咯~ + +### 具体实现 + +```python +sys.setrecursionlimit(100000) + +class Solution: + def lastRemaining(self, n: int, m: int) -> int: + return self.f(n, m) + + def f(self, n, m): + if n == 0: + return 0 + x = self.f(n - 1, m) + return (m + x) % n +``` + +各位大佬的图实在画得太好了,我就不献丑了(逃 + ## 面试题68 - I. 二叉搜索树的最近公共祖先 同:235. 二叉搜索树的最近公共祖先 \ No newline at end of file From 48f461bff69db28aa94b8b2e16ae8e8040054ef4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 1 Apr 2020 22:04:12 +0800 Subject: [PATCH 089/181] =?UTF-8?q?=F0=9F=90=B1(stack):=201111.=20?= =?UTF-8?q?=E6=9C=89=E6=95=88=E6=8B=AC=E5=8F=B7=E7=9A=84=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=E6=B7=B1=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 77 +++++++++++++++++++++++++++++ docs/data-structure/stack/README.md | 24 +++++++++ 2 files changed, 101 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 839cc097d..1537e9a1d 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -490,6 +490,83 @@ class MyHashSet: # param_3 = obj.contains(key) ``` +## 706. 设计哈希映射 + +[原题链接](https://leetcode-cn.com/problems/design-hashmap/) + +### 思路 + +1. 哈希映射设计:如何通过 `key` 找到合适的桶 +2. 哈希碰撞处理:许多 `key` 都映射在一个桶里,如何进行这些值的存储与查找 + +```python +class Bucket: + def __init__(self): + self.bucket = [] + + def put(self, key, value): + for i in range(len(self.bucket)): + k, v = self.bucket[i][0], self.bucket[i][1] + if k == key: + self.bucket[i] = (key, value) + return + self.bucket.append((key, value)) + + def get(self, key): + for i in range(len(self.bucket)): + k, v = self.bucket[i][0], self.bucket[i][1] + if k == key: + return v + return -1 + + def remove(self, key): + for i, kv in enumerate(self.bucket): + if key == kv[0]: + # 删除元素问题 + del self.bucket[i] + +class MyHashMap: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.bucket_count = 2069 + self.hash_map = [Bucket() for _ in range(self.bucket_count)] + + + def put(self, key: int, value: int) -> None: + """ + value will always be non-negative. + """ + bucket_num = key % self.bucket_count + self.hash_map[bucket_num].put(key, value) + + + def get(self, key: int) -> int: + """ + Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key + """ + bucket_num = key % self.bucket_count + return self.hash_map[bucket_num].get(key) + + + def remove(self, key: int) -> None: + """ + Removes the mapping of the specified value key if this map contains a mapping for the key + """ + bucket_num = key % self.bucket_count + self.hash_map[bucket_num].remove(key) + + + +# Your MyHashMap object will be instantiated and called as such: +# obj = MyHashMap() +# obj.put(key,value) +# param_2 = obj.get(key) +# obj.remove(key) +``` + ### 解二:链表模拟 ## 1160. 拼写单词 diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index d92f4a5b3..1707ab760 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -1023,4 +1023,28 @@ class Solution: push_i += 1 return len(stack) == 0 +``` + +## 1111. 有效括号的嵌套深度 + +[原题链接](https://leetcode-cn.com/problems/maximum-nesting-depth-of-two-valid-parentheses-strings/) + +### 解一:栈匹配 + +1. 通过栈匹配来计算每个括号所属的深度 +2. 把同一深度的括号平均分配给 A 和 B + +```python +class Solution: + def maxDepthAfterSplit(self, seq: str) -> List[int]: + depth = 0 + ans = [] + for s in seq: + if s == '(': + depth += 1 + ans.append(depth % 2) + else: + ans.append(depth % 2) + depth -= 1 + return ans ``` \ No newline at end of file From 9a0656cf48f47ed628770221a243fa2591a0db6b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 4 Apr 2020 15:43:33 +0800 Subject: [PATCH 090/181] =?UTF-8?q?=F0=9F=90=B1(stack):=2042.=20=E6=8E=A5?= =?UTF-8?q?=E9=9B=A8=E6=B0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 45abd41aa..fdc476b8c 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -565,6 +565,50 @@ class Solution(object): return area ``` +### 解二:单调栈 + +维护一个单调栈:即从栈底到栈顶元素逐渐减小。 + +在遍历墙的过程中: + +1. 墙的高度小于或等于栈顶元素:入栈,此时不会产生积水 +2. 墙的高度大于栈顶元素:栈顶元素出栈,此时栈顶元素处会产生积水,产生积水的面积为:(该位置左右墙体的最小高度 - 栈顶元素高度)* 左右墙体距离差 + +```python +class Solution: + def trap(self, height: List[int]) -> int: + length = len(height) + if length == 0: + return 0 + + stack = [] + # 第一个元素入栈 + stack.append(0) + ans = 0 + for i in range(1, length): + # 栈顶元素 + top = stack[-1] + h = height[i] + # 循环 pop + while len(stack) != 0 and height[stack[-1]] < h: + # 弹出栈顶元素 + tmp = stack.pop() + # 存在墙才计算积水 + if len(stack) == 0: + break + # 计算左右两侧高度 min + diff = min(height[stack[-1]], h) + distance = i - stack[-1] - 1 + ans += distance * (diff - height[tmp]) + + stack.append(i) + + return ans +``` + +- 时间复杂度:$O(n)$ +- 空间复杂度:$O(n)$ + ## 48. 旋转图像 From 73efe944accf50170e7406f3de20d6d6fec5278c Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 5 Apr 2020 13:30:46 +0800 Subject: [PATCH 091/181] =?UTF-8?q?=F0=9F=90=B1(design):=20460.=20LFU?= =?UTF-8?q?=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/_sidebar.md | 1 + docs/design/README.md | 68 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 docs/design/README.md diff --git a/docs/_sidebar.md b/docs/_sidebar.md index dec7b12a5..c746af3b8 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -37,6 +37,7 @@ * [双指针](algorithm/double-pointer/) * [滑动窗口](algorithm/sliding-window/) * [其他](algorithm/other/) + * [3.3 设计](design/README.md) * 3.3 竞赛 * [周赛](weekly/) * [双周赛](biweekly/) diff --git a/docs/design/README.md b/docs/design/README.md new file mode 100644 index 000000000..ebfb291d5 --- /dev/null +++ b/docs/design/README.md @@ -0,0 +1,68 @@ +## 460. LFU缓存 + +[原题链接](https://leetcode-cn.com/problems/lfu-cache/) + +### 解一:简单直白法 + +存储每个页的访问频率 `cnt` 和最近访问标记 `mark`。 + +```python +class Page: + def __init__(self, val, cnt, mark): + self.val = val + self.cnt = cnt + self.mark = mark + +class LFUCache: + + def __init__(self, capacity: int): + self.cap = capacity + self.cache = dict() + self.mark = 0 + + def get(self, key: int) -> int: + if key not in self.cache: + return -1 + self.cache[key].cnt += 1 + self.mark += 1 + self.cache[key].mark = self.mark + return self.cache[key].val + + def put(self, key: int, value: int) -> None: + if key in self.cache: + cur_cnt = self.cache[key].cnt + 1 + self.mark += 1 + self.cache[key] = Page(value, cur_cnt, self.mark) + return + + # 判断是否超过 + if len(self.cache) < self.cap: + # 直接写入 + self.cache[key] = Page(value, 0, self.mark) + return + + cnt = float('inf') + mark = float('inf') + del_key = None + # 获取最近最少使用的键,cnt 最小,然后 mark 最小 + for k in self.cache: + page = self.cache[k] + if page.cnt < cnt: + cnt = page.cnt + mark = page.mark + del_key = k + if page.cnt == cnt and page.mark < mark: + mark = page.mark + del_key = k + + if del_key is not None: + self.cache.pop(del_key) + # 写入新的值 + self.mark += 1 + self.cache[key] = Page(value, 0, self.mark) + +# Your LFUCache object will be instantiated and called as such: +# obj = LFUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) +``` \ No newline at end of file From ad1c52cd9f557b7d5a050c0b4f2b84c4433c0e22 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 6 Apr 2020 19:39:03 +0800 Subject: [PATCH 092/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=2072.=20?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E8=B7=9D=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index c528b4e0a..553726b5c 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -444,6 +444,45 @@ class Solution(object): return cur ``` +## 72. 编辑距离 + +[原题链接](https://leetcode-cn.com/problems/edit-distance/) + +### 动态规划 + +用 `dp[i][j]` 表示 `words1` 前 `i` 个字符到 `words2` 前 `j` 个字符的编辑距离。 + +```python +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + length1 = len(word1) + length2 = len(word2) + # 如果有字符串为空 + if length1 == 0 or length2 == 0: + return length1 + length2 + + dp = [[0 for _ in range(length2 + 1)] for _ in range(length1 + 1)] + + # 初始化边界值 + for i in range(length1 + 1): + dp[i][0] = i + for j in range(length2 + 1): + dp[0][j] = j + + # 计算 dp + # 从字符串末尾插入或更新字符 + # 状态转移方程: + # 末尾相同时:dp[i][j] = dp[i - 1][j - 1] + # 末尾不同时(替换或插入操作):dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + 1) + for i in range(1, length1 + 1): + for j in range(1, length2 + 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 - 1][j], dp[i][j - 1]) + 1 + + return dp[length1][length2] +``` ## 95. 不同的二叉搜索树 II From 86dce053eef9b359a10ad96bdd2c2c983653ed27 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 6 Apr 2020 19:52:31 +0800 Subject: [PATCH 093/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=2072.=20?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E8=B7=9D=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 553726b5c..675345374 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -452,6 +452,10 @@ class Solution(object): 用 `dp[i][j]` 表示 `words1` 前 `i` 个字符到 `words2` 前 `j` 个字符的编辑距离。 + + +#### **Python** + ```python class Solution: def minDistance(self, word1: str, word2: str) -> int: @@ -484,6 +488,47 @@ class Solution: return dp[length1][length2] ``` +#### **Go** + +```go +func minDistance(word1 string, word2 string) int { + length1 := len(word1) + length2 := len(word2) + var dp = make([][]int, length1 + 1) + for i := 0; i < length1 + 1; i++ { + dp[i] = make([]int, length2 + 1) + } + // 初始化 + for i := 0; i < length1 + 1; i++ { + dp[i][0] = i + } + for j := 0; j < length2 + 1; j++ { + dp[0][j] = j + } + // 计算 dp + for i := 1; i < length1 + 1; i ++ { + for j := 1; j < length2 + 1; j++ { + if word1[i - 1] == word2[j - 1] { + dp[i][j] = dp[i - 1][j - 1] + } else { + dp[i][j] = getMin(dp[i - 1][j - 1], getMin(dp[i - 1][j], dp[i][j - 1])) + 1 + } + } + } + return dp[length1][length2] +} + +func getMin(a int, b int) int { + if a < b { + return a + } + return b +} +``` + + + + ## 95. 不同的二叉搜索树 II [原题链接](https://leetcode-cn.com/problems/unique-binary-search-trees-ii/) From 78b3efc95ba8a6dd7ba889f23c056f7fa0c32baf Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 7 Apr 2020 23:20:13 +0800 Subject: [PATCH 094/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2001.07.=20=E6=97=8B=E8=BD=AC=E7=9F=A9?= =?UTF-8?q?=E9=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index 791ff54d6..c617d3111 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -68,6 +68,32 @@ func compressString(S string) string { +## 面试题 01.07. 旋转矩阵 + +[原题链接](https://leetcode-cn.com/problems/rotate-matrix-lcci/) + +### 思路 + +找出要进行顺时针旋转的四个位置分别是:`(i, j) (j, n-i-1) (n-i-1, n-j-1)` + +```python +class Solution: + def rotate(self, matrix: List[List[int]]) -> None: + """ + Do not return anything, modify matrix in-place instead. + """ + n = len(matrix) + # 旋转交换的四个位置:(i, j) (j, n-i-1) (n-i-1, n-j-1) (n-j-1, i) + # 枚举范围:宽 (n + 1)/2 高 n/2 + for i in range(n // 2): + for j in range((n + 1) // 2): + temp = matrix[i][j] + matrix[i][j] = matrix[n - j - 1][i] + matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1] + matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1] + matrix[j][n - i - 1] = temp +``` + ## 面试题03. 数组中重复的数字 [原题链接](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/) From aad5cef9567b3c249b8fbdbc13064aef90f0b9ce Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 11 Apr 2020 15:52:00 +0800 Subject: [PATCH 095/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20887.=20?= =?UTF-8?q?=E9=B8=A1=E8=9B=8B=E6=8E=89=E8=90=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 91 ++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 675345374..a1a6b2171 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1355,6 +1355,97 @@ class Solution: return dp[nums_list[-1]] ``` +## 887. 鸡蛋掉落 + +[原题链接](https://leetcode-cn.com/problems/super-egg-drop/) + +### 动态规划 + +`(K, N)` 中 `K` 表示鸡蛋数,`N` 表示楼层数量。那么从 `X` 层楼扔鸡蛋时: + +- 鸡蛋碎了:状态变为 `(K-1, X-1)` +- 鸡蛋没碎:状态变为 `(K, N - X)` + +有状态转移方程如下: + +$dp(K, N) = 1 + min(max(dp(K - 1, X - 1), dp(K, N - X)))$ + +初始化值: + +1. 当只有 1 个鸡蛋时,有几层楼就要扔几次 +2. 当只有 1 层楼时,只要扔一次 +3. 0 层或 0 个鸡蛋时均初始化为 0 +4. 因为要求「最小值」,所以初始化其他数值时尽量给到最大值,可以赋值楼层数量 + 1 + +```go +func superEggDrop(K int, N int) int { + var dp [][]int + // 初始化 + for i := 0; i <= K; i++ { + tmp := make([]int, N + 1) + for j := 0; j <= N; j++ { + tmp[j] = j + 1 + if i == 0 { + // 0 个蛋 + tmp[j] = 0 + } + if i == 1 { + // 1 个蛋 + tmp[j] = j + } + if j == 0 { + // 0 层楼 + tmp[j] = 0 + } + if j == 1 { + // 1 层楼 + tmp[j] = 1 + } + } + dp = append(dp, tmp) + } + + for i:=2; i <= K; i++ { + for j := 2; j <= N; j++ { + left := 1 + right := j + for left <= right { + mid := (left + right) / 2 + if dp[i][j - mid] < dp[i - 1][mid - 1] { + right = mid - 1 + } else { + left = mid + 1 + } + } + t1 := j + 1 + t2 := j + 1 + if left <= j { + t1 = getMax(dp[i][j - left], dp[i - 1][left - 1]) + } + if right >= 1 { + t2 = getMax(dp[i][j - right], dp[i - 1][right - 1]) + } + dp[i][j] = getMin(t1, t2) + 1 + } + } + return dp[K][N] +} + +func getMax(a int, b int) int { + if a > b { + return a + } + return b +} + +func getMin(a int, b int) int { + if a < b { + return a + } + return b +} +``` + ## 898. 子数组按位或操作 [原题链接](https://leetcode-cn.com/problems/bitwise-ors-of-subarrays/) From 84ddeadc85748b00f67c96f1d27bf2408bf0c8e4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 12 Apr 2020 13:52:00 +0800 Subject: [PATCH 096/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2016.03.=20=E4=BA=A4=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 83 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index c617d3111..d6770bd8a 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -300,6 +300,89 @@ class Solution: return max(dp[0][length - 1], dp[1][length - 1]) ``` +## 面试题 16.03. 交点 + +[原题链接](https://leetcode-cn.com/problems/intersection-lcci/) + +### 思路 + +解方程题目。。。就是代码写得太丑了。 + +```python +class Solution: + def intersection(self, start1: List[int], end1: List[int], start2: List[int], end2: List[int]) -> List[float]: + # kx + b = y + # 调换位置:x1 < x2, x3 < x4,避免后续判断 + x1, y1 = start1[0], start1[1] + x2, y2 = end1[0], end1[1] + if x1 > x2: + x1, x2 = x2, x1 + y1, y2 = y2, y1 + x3, y3 = start2[0], start2[1] + x4, y4 = end2[0], end2[1] + if x3 > x4: + x3, x4 = x4, x3 + y3, y4 = y4, y3 + + # 判断是否有交点 + if x2 < x3 or x4 < x1 or max(y1, y2) < min(y3, y4) or max(y3, y4) < min(y1, y2): + # 此时两线段不会有交点 + return ans + + # 计算斜率和参数 + b1, b2 = 0, 0 + if x1 == x2: + k1 = None + else: + k1 = (y2 - y1) / (x2 - x1) + b1 = y1 - k1 * x1 + if x3 == x4: + k2 = None + else: + k2 = (y4 - y3) / (x4 - x3) + b2 = y3 - k2 * x3 + + # print(k1, b1, k2, b2) + + # 判断具体条件 + if k1 is None and k2 is None: + if x1 == x3: + # 垂直重合,判断 y 的交点 + if min(y1, y2) <= max(y3, y4): + return [x1, min(y1, y2)] + if min(y3, y4) <= max(y1, y2): + return [x1, min(y3, y4)] + return [] + + if k1 is None: + return [x1, k2 * x1 + b2] + + if k2 is None: + return [x3, k1 * x3 + b1] + + if k1 == k2: + # 平行或重叠 + if b1 == b2: + # 相交 + # 找 x 区间的相交点 + if x3 >= x1 and x3 <= x2: + return [x3, y3] + if x4 >= x1 and x4 <= x2: + return [x4, y4] + if x1 >= x3 and x1 <= x4: + return [x1, y1] + if x2 >= x3 and x2 <= x4: + return [x2, y2] + return [] + + # 相交,求交点 + x = (b2 - b1) / (k1 - k2) + y = k1 * x + b1 + if x < x1 or x < x3 or x > x2 or x > x4 or y < min(y1, y2) or y < min(y3, y4) or y > max(y1, y2) or y > max(y3, y4): + return [] + return [x, y] +``` + ## 面试题24. 反转链表 [原题链接](https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/) From 75dd5adce5549e3d45b6a73d0d939aaca92852a7 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 13 Apr 2020 21:53:50 +0800 Subject: [PATCH 097/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20355.=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E6=8E=A8=E7=89=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 94 ++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 1537e9a1d..af8bc021d 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -195,6 +195,100 @@ class Solution(object): 排序 + 双指针,不需要额外空间。 +## 355. 设计推特 + +[原题链接](https://leetcode-cn.com/problems/design-twitter/) + +### 偷懒排序法 + +```python +class Node: + def __init__(self, time, tweet_id, nxt): + """ + 链表节点 + """ + self.time = 0 + self.nxt = nxt + self.tweet_id = tweet_id + +class Twitter: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.time = 0 + # 用户哈希 + self.tweets = dict() + self.followers = dict() + + + def postTweet(self, userId: int, tweetId: int) -> None: + """ + Compose a new tweet. + """ + # node = Node(self.time, tweetId, None) + # if userId in self.tweets: + # head = self.tweet[userId] + # node.nxt = head + # self.tweets[userId] = node + # self.time += 1 + if userId not in self.tweets: + self.tweets[userId] = [] + self.tweets[userId].append([self.time, tweetId]) + self.time += 1 + + + def getNewsFeed(self, userId: int) -> List[int]: + """ + Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. + """ + ans = [] + # 取出关注的用户 + followers = self.followers.get(userId, set()) + # print(self.tweets) + tweets = [] + if userId in self.tweets: + tweets = self.tweets[userId] + # print(tweets) + # print(followers) + for follower in followers: + # tweets.extend(self.tweets[follower]) + if follower in self.tweets: + tweets = tweets + self.tweets[follower] + tweets.sort(key=lambda x: x[0], reverse=True) + # print(tweets) + # print(tweets) + # print([x[1] for x in tweets[:10]]) + return [x[1] for x in tweets[:10]] + + def follow(self, followerId: int, followeeId: int) -> None: + """ + Follower follows a followee. If the operation is invalid, it should be a no-op. + """ + if followerId == followeeId: + # 不允许自己关注自己 + return + if followerId not in self.followers: + self.followers[followerId] = set() + self.followers[followerId].add(followeeId) + + + def unfollow(self, followerId: int, followeeId: int) -> None: + """ + Follower unfollows a followee. If the operation is invalid, it should be a no-op. + """ + if followerId not in self.followers: + return + self.followers[followerId].discard(followeeId) + +# Your Twitter object will be instantiated and called as such: +# obj = Twitter() +# obj.postTweet(userId,tweetId) +# param_2 = obj.getNewsFeed(userId) +# obj.follow(followerId,followeeId) +# obj.unfollow(followerId,followeeId) +``` ## 454. 四数相加 II From 6b16638c6921068938e95dbfbafba5254c684614 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 15 Apr 2020 21:04:55 +0800 Subject: [PATCH 098/181] =?UTF-8?q?=F0=9F=90=B1(bfs):=20542.=2001=20?= =?UTF-8?q?=E7=9F=A9=E9=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/research/bfs/README.md | 87 +++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/docs/algorithm/research/bfs/README.md b/docs/algorithm/research/bfs/README.md index d85b3c36b..c42eaff7d 100644 --- a/docs/algorithm/research/bfs/README.md +++ b/docs/algorithm/research/bfs/README.md @@ -62,6 +62,93 @@ class Solution(object): return res ``` +## 542. 01 矩阵 + +[原题链接](https://leetcode-cn.com/problems/01-matrix/) + +### BFS:以 1 为源(超时) + +```python +class Solution: + def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]: + m = len(matrix) + if m == 0: + return [] + n = len(matrix[0]) + + ans = [[0 for _ in range(n)] for _ in range(m)] + + for i in range(m): + for j in range(n): + if matrix[i][j] == 0: + # 0 不处理 + continue + mark = [[0 for _ in range(n)] for _ in range(m)] + step = 0 + queue = [(i, j, step)] + while len(queue) > 0: + # bfs + x, y, s = queue[0][0], queue[0][1], queue[0][2] + del queue[0] + if mark[x][y]: + # 已经访问过,跳过 + continue + # 处理 + mark[x][y] = 1 # 访问标记 + if matrix[x][y] == 0: + # 找到 0,进行标记,不继续遍历 + ans[i][j] = s + break + + # 否则加入上下左右 + directions = [[0, 1], [0, -1], [-1, 0], [1, 0]] + for d in directions: + n_x, n_y = x + d[0], y + d[1] + if n_x >= 0 and n_x < m and n_y >= 0 and n_y < n and mark[n_x][n_y] == 0: + # 坐标符合要求 + # print(n_x, n_y, s + 1) + queue.append((n_x, n_y, s + 1)) + + return ans +``` + +### BFS:以 0 为源 + +把所有 0 放入队列,每个 0 逐个向外 BFS 一圈标记相邻的 1,再把 BFS 到的 1 入队列…… + +```python +class Solution: + def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]: + m = len(matrix) + if m == 0: + return [] + n = len(matrix[0]) + + queue = [] + + for i in range(m): + for j in range(n): + # 把 0 放入队列 + if matrix[i][j] == 0: + queue.append((i, j)) + else: + # 把 1 标记为未访问过的结点 + matrix[i][j] = -1 + directions = [[0, 1], [0, -1], [1, 0], [-1, 0]] + while len(queue) > 0: + x, y = queue[0][0], queue[0][1] + del queue[0] + for d in directions: + n_x, n_y = x + d[0], y + d[1] + if n_x >= 0 and n_x < m and n_y >= 0 and n_y < n and matrix[n_x][n_y] == -1: + matrix[n_x][n_y] = matrix[x][y] + 1 + queue.append((n_x, n_y)) + + return matrix +``` + +- 时间复杂度:$O(m * n)$ + ## 1162. 地图分析 [原题链接](https://leetcode-cn.com/problems/as-far-from-land-as-possible/) From d1c7f67bd98d98ed76749484423f010db1cfeab6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 16 Apr 2020 21:25:35 +0800 Subject: [PATCH 099/181] =?UTF-8?q?=F0=9F=90=B1(array):=2056.=20=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E5=8C=BA=E9=97=B4=20=E8=A1=A5=E5=85=85=E5=A4=8D?= =?UTF-8?q?=E6=9D=82=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index fdc476b8c..ead6a4773 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -817,6 +817,10 @@ class Solution(object): return res ``` +复杂度: + +- 时间复杂度:$O(nlogn)$ +- 空间复杂度:$O(n)$ ## 66. 加一 From 3d4fb75aff4a07fd9f6034193104a51be4168fc1 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 17 Apr 2020 18:59:34 +0800 Subject: [PATCH 100/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=2055.=20?= =?UTF-8?q?=E8=B7=B3=E8=B7=83=E6=B8=B8=E6=88=8F=20=E4=BA=8C=E6=AC=A1?= =?UTF-8?q?=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index a1a6b2171..73b695f8b 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -192,7 +192,7 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/jump-game/comments/) -### 思路 +### 思路一 数组从后往前遍历: @@ -215,6 +215,7 @@ class Solution(object): end = length - 1 for i in reversed(range(length - 1)): if i + nums[i] >= end: + # 把最后一个位置不断往前推 end = i if end == 0: @@ -223,6 +224,31 @@ class Solution(object): return False ``` +### 思路二 + +用 `mark[i]` 标记是否可以到达位置 `i`。 + +```python +class Solution: + def canJump(self, nums: List[int]) -> bool: + length = len(nums) + mark = [False for _ in range(length)] + mark[0] = True + begin = 1 + for i in range(length): + n = nums[i] + if mark[i]: + # 可以到达 + for j in range(begin - i, n + 1): + jump = i + j + if jump == length - 1: + return True + if jump >= length: + break + mark[jump] = True + begin = i + n + 1 if i + n + 1 < length else length - 1 + return mark[length - 1] +``` ## 62. 不同路径 From aaa8cdc6df1c7476ab833256e17935303a15df5a Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 20 Apr 2020 19:43:40 +0800 Subject: [PATCH 101/181] =?UTF-8?q?=F0=9F=90=B1(bfs):=20200.=20=E5=B2=9B?= =?UTF-8?q?=E5=B1=BF=E6=95=B0=E9=87=8F=20=E8=A1=A5=E5=85=85=20golang=20?= =?UTF-8?q?=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/research/bfs/README.md | 65 ++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/research/bfs/README.md b/docs/algorithm/research/bfs/README.md index c42eaff7d..82007b201 100644 --- a/docs/algorithm/research/bfs/README.md +++ b/docs/algorithm/research/bfs/README.md @@ -2,7 +2,7 @@ [原题链接](https://leetcode-cn.com/problems/number-of-islands/) -### 思路 +### BFS 广度优先搜索 BFS。总结一下思想就是:一旦发现岛屿就找到与它相邻的岛屿并将它们沉没,那么下次再发现的岛屿就是新大陆了。 @@ -15,6 +15,10 @@ 3. 将岛屿沉没("1" -> "0"),防止后续重复计算 4. 使用广度优先遍历,查找该岛屿的四个相邻位置上是否还有岛屿,如果发现了岛屿就把它加入队列并且沉没 + + +#### **Python** + ```python class Solution(object): def numIslands(self, grid): @@ -62,6 +66,65 @@ class Solution(object): return res ``` +#### **Go** + +```go +func numIslands(grid [][]byte) int { + var ans int + + m := len(grid) + if m == 0 { + return ans + } + n := len(grid[0]) + + for i := 0; i < m; i++ { + for j := 0; j < n; j++ { + if grid[i][j] == '1' { + ans += 1 + // 是岛屿,bfs + tmp := []int{i, j} + queue := make([][]int, 0) + queue = append(queue, tmp) + for len(queue) > 0 { + position := queue[0] + // 删除第一个元素 + queue = queue[1:] + x := position[0] + y := position[1] + // 四个方向 (1, 0) (-1, 0) (0, 1) (0, -1) + if x + 1 < m && grid[x + 1][y] == '1' { + tmp := []int{x + 1, y} + grid[x + 1][y] = '0' + queue = append(queue, tmp) + } + if x - 1 >= 0 && grid[x - 1][y] == '1' { + tmp := []int{x - 1, y} + grid[x - 1][y] = '0' + queue = append(queue, tmp) + } + if y + 1 < n && grid[x][y + 1] == '1' { + tmp := []int{x, y + 1} + grid[x][y + 1] = '0' + queue = append(queue, tmp) + } + if y - 1 >= 0 && grid[x][y - 1] == '1' { + tmp := []int{x, y - 1} + grid[x][y - 1] = '0' + queue = append(queue, tmp) + } + } + // print(queue) + } + } + } + + return ans +} +``` + + + ## 542. 01 矩阵 [原题链接](https://leetcode-cn.com/problems/01-matrix/) From a7f3cb36c561c45b1f3367bf5a2c752ae7059e53 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 21 Apr 2020 21:47:42 +0800 Subject: [PATCH 102/181] =?UTF-8?q?=F0=9F=90=B1(sliding-window):=201248.?= =?UTF-8?q?=20=E7=BB=9F=E8=AE=A1=E3=80=8C=E4=BC=98=E7=BE=8E=E5=AD=90?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/sliding-window/README.md | 32 ++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/sliding-window/README.md b/docs/algorithm/sliding-window/README.md index 2a4a3d733..fa0cab83a 100644 --- a/docs/algorithm/sliding-window/README.md +++ b/docs/algorithm/sliding-window/README.md @@ -212,4 +212,34 @@ class Solution: ``` - 时间复杂度:$O(l1 + (l2 - l1))$($l1$ 为字符串 s1 长度,$l2$ 为字符串 s2 长度) -- 空间复杂度:$O(1)$ \ No newline at end of file +- 空间复杂度:$O(1)$ + +## 1248. 统计「优美子数组」 + +[原题链接](https://leetcode-cn.com/problems/count-number-of-nice-subarrays/) + +### 滑动窗口 + +记录奇数的位置。固定 k 个奇数,子数组的个数 = 第一个奇数左边偶数的个数 * 最后一个奇数右边偶数的个数。 + +```python +class Solution: + def numberOfSubarrays(self, nums: List[int], k: int) -> int: + ans = 0 + # 开始位置 + odd = [-1] + # 记录奇数下标 + for i in range(len(nums)): + if nums[i] % 2 == 1: + odd.append(i) + # 添加结束位置 + odd.append(len(nums)) + + # 遍历奇数数组 + for j in range(1, len(odd) - k): + # 从第 i 个到 i + k - 1 + # 第 i 个奇数前面的偶数个数 * 第 i + k - 1 后面的偶数个数 + ans += (odd[j] - odd[j - 1]) * (odd[j + k] - odd[j + k - 1]) + + return ans +``` \ No newline at end of file From 93b70510ff45cd4a7fa1e613b1047f6009a6c147 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 22 Apr 2020 18:37:50 +0800 Subject: [PATCH 103/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20199.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=8F=B3=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/bfs/README.md | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/data-structure/tree/bfs/README.md b/docs/data-structure/tree/bfs/README.md index 821f505e6..c42c4db32 100644 --- a/docs/data-structure/tree/bfs/README.md +++ b/docs/data-structure/tree/bfs/README.md @@ -230,6 +230,44 @@ class Solution: +## 199. 二叉树的右视图 + +[原题链接](https://leetcode-cn.com/problems/binary-tree-right-side-view/) + +### BFS 层级别离 + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def rightSideView(self, root: TreeNode) -> List[int]: + ans = [] + queue = [root] + while len(queue) > 0: + q_length = len(queue) + for i in range(q_length): + first = queue[0] + del queue[0] + if first is None: + continue + if i == q_length - 1: + ans.append(first.val) + if first.left is not None: + queue.append(first.left) + if first.right is not None: + queue.append(first.right) + + return ans +``` + +- 时间复杂度:$O(n)$ +- 空间复杂度:$O(n)$ + ## 297. 二叉树的序列化与反序列化 [原题链接](https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/) From fdc4d169109314b30aeddc69471e63e5485ec691 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 23 Apr 2020 20:57:57 +0800 Subject: [PATCH 104/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=98=2008.11.=20=E7=A1=AC=E5=B8=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index d6770bd8a..d27e73473 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -300,6 +300,27 @@ class Solution: return max(dp[0][length - 1], dp[1][length - 1]) ``` +## 面试题 08.11. 硬币 + +[原题链接](https://leetcode-cn.com/problems/coin-lcci/) + +### 思路 + +1. 遍历所有硬币 +2. `dp[i - coin]` 表示去掉 coin 面额后的组合数量 + +```python +class Solution: + def waysToChange(self, n: int) -> int: + coins = [1, 5, 10, 25] + dp = [0 for _ in range(n + 1)] + dp[0] = 1 + for coin in coins: + for i in range(coin, n + 1): + dp[i] = (dp[i] + dp[i - coin]) % 1000000007 + return dp[n] +``` + ## 面试题 16.03. 交点 [原题链接](https://leetcode-cn.com/problems/intersection-lcci/) From c437b3af69e5e05817e499a6e61cbc3336c50dfb Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 26 Apr 2020 21:01:29 +0800 Subject: [PATCH 105/181] =?UTF-8?q?=F0=9F=90=B1(divide):=2023.=20=E5=90=88?= =?UTF-8?q?=E5=B9=B6K=E4=B8=AA=E6=8E=92=E5=BA=8F=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/divide-and-conquer/README.md | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/algorithm/divide-and-conquer/README.md b/docs/algorithm/divide-and-conquer/README.md index 388ef5982..4ac652481 100644 --- a/docs/algorithm/divide-and-conquer/README.md +++ b/docs/algorithm/divide-and-conquer/README.md @@ -1,3 +1,53 @@ +## 23. 合并K个排序链表 + +[原题链接](https://leetcode-cn.com/problems/merge-k-sorted-lists/) + +### 解一:顺序合并 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def mergeKLists(self, lists: List[ListNode]) -> ListNode: + length = len(lists) + i = 0 + ans = ListNode(0) + head = ans + while len(lists) > 0: + min_index = 0 + min_val = float('inf') + min_node = None + for i in range(len(lists)): + # 遍历数组 + node = lists[i] + if node is None: + continue + if node.val < min_val: + min_index = i + min_val = node.val + min_node = node + # 最小值进入链表 + if head is not None: + head.next = min_node + head = head.next + # 处理最小值 + # next_node = min_node.next + if min_node is None or min_node.next is None: + del lists[min_index] + else: + lists[min_index] = min_node.next + return ans.next +``` + +k 个链表,n 个节点 + +- 时间复杂度:$O(k*n)$ +- 空间复杂度:$O(n)$ + ## 241. 为运算表达式设计优先级 [原题链接](https://leetcode-cn.com/problems/different-ways-to-add-parentheses/) From 8053cf4cf4ae7af3c8180d20efac05b9419f8cab Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 27 Apr 2020 20:07:47 +0800 Subject: [PATCH 106/181] =?UTF-8?q?=F0=9F=90=B1(array):=2033.=20=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E6=97=8B=E8=BD=AC=E6=8E=92=E5=BA=8F=E6=95=B0=E7=BB=84?= =?UTF-8?q?=20=E8=A1=A5=E5=85=85=20golang=20=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 86 +++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index ead6a4773..2624637b1 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -419,6 +419,10 @@ func removeElement(nums []int, val int) int { - 有序:使用二分查找 - 无序:继续划分 + + +#### **Python** + ```python class Solution(object): def search(self, nums, target): @@ -449,6 +453,88 @@ class Solution(object): return -1 ``` +#### **Go** + +```go +func search(nums []int, target int) int { + length := len(nums) + left := 0 + right := length - 1 + for left <= right { + mid := (left + right) / 2 + // fmt.Println(left, right, mid) + if nums[mid] == target { + return mid + } + if nums[mid] <= nums[right] { + // 右边是顺序数组 + if nums[mid] <= target && target <= nums[right] { + // 判断是否在右边 + left = mid + 1 + } else { + right = mid - 1 + } + } else { + // 左边是顺序数组 + if nums[left] <= target && target <= nums[mid] { + // 判断是否在左边 + right = mid - 1 + } else { + left = mid + 1 + } + } + } + + return -1 +} +``` + + + +---- + +2020.04.27 复盘: + +想复杂了: + +```python +class Solution: + def search(self, nums: List[int], target: int) -> int: + length = len(nums) + left = 0 + right = length - 1 + while left <= right: + mid = (left + right) // 2 + # print(left, right, mid) + if nums[mid] == target: + return mid + if nums[left] <= nums[right]: + # 顺序数组 + if nums[mid] > target: + right = mid - 1 + else: + left = mid + 1 + else: + # 非顺序数组:左侧的值比右边的大,说明旋转点在中间 + if target < nums[left] and target > nums[right]: + # 这种情况找不到 + return -1 + if nums[mid] >= nums[left]: + # 旋转点在右边 + if target <= nums[right] or target > nums[mid]: + # 寻找的点比中间值大或比右侧点小 + left = mid + 1 + else: + right = mid - 1 + else: + # 旋转点在左边 + if target < nums[mid] or target >= nums[left]: + right = mid - 1 + else: + left = mid + 1 + return -1 +``` + ## 36. 有效的数独 From ae176cc021f7ab57b16b2fcab55354a65e227b87 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 28 Apr 2020 20:02:01 +0800 Subject: [PATCH 107/181] =?UTF-8?q?=F0=9F=90=B1(offer):=20=E9=9D=A2?= =?UTF-8?q?=E8=AF=95=E9=A2=9856=20-=20I.=20=E6=95=B0=E7=BB=84=E4=B8=AD?= =?UTF-8?q?=E6=95=B0=E5=AD=97=E5=87=BA=E7=8E=B0=E7=9A=84=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/offer/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/offer/README.md b/docs/offer/README.md index d27e73473..71737b662 100644 --- a/docs/offer/README.md +++ b/docs/offer/README.md @@ -450,6 +450,37 @@ class Solution: return cur ``` +## 面试题56 - I. 数组中数字出现的次数 + +[原题链接](https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/) + +### 思路:异或 + +1. 求出所有数异或的结果 +2. 结果中为 1 的位表示两个数不同数字的位 +3. 根据这个为 1 的位置把 `nums` 分成两组分别异或就可以得出结果 + +```python +class Solution: + def singleNumbers(self, nums: List[int]) -> List[int]: + ret = 0 + for n in nums: + ret ^= n + # 找出从右到左第一个为 1 的数 + index = 0 + while ret & 1 == 0: + # 右移 1 位 + ret >>= 1 + index += 1 + a, b = 0, 0 + for n in nums: + if (n >> index) & 1 == 0: + a ^= n + else: + b ^= n + return [a, b] +``` + ## 面试题57 - II. 和为s的连续正数序列 [原题链接](https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/) From bf47953e009e39edc4b38823d2ab41a152f17b64 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 29 Apr 2020 21:22:24 +0800 Subject: [PATCH 108/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=201095.=20?= =?UTF-8?q?=E5=B1=B1=E8=84=89=E6=95=B0=E7=BB=84=E4=B8=AD=E6=9F=A5=E6=89=BE?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 373b67f26..8e3115273 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -718,4 +718,71 @@ func getMax(a int, b int) int { } ``` - \ No newline at end of file + + +## 1095. 山脉数组中查找目标值 + +[原题链接](https://leetcode-cn.com/problems/find-in-mountain-array/) + +### 思路 + +核心思想二分法: + +1. 通过二分法寻找峰值 +2. 二分法在峰值左侧寻找目标 +3. 如果目标不在左侧,使用二分法在峰值右侧寻找目标 + +```python +# """ +# This is MountainArray's API interface. +# You should not implement it, or speculate about its implementation +# """ +#class MountainArray: +# def get(self, index: int) -> int: +# def length(self) -> int: + +class Solution: + def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int: + length = mountain_arr.length() + # print(length) + # 找到峰值 + left = 0 + right = length - 1 + while left < right: + mid = (left + right) // 2 + if mountain_arr.get(mid + 1) > mountain_arr.get(mid): + # 峰值在右侧 + left = mid + 1 + else: + right = mid + # 峰值 + peak = left + + # 左侧二分查找 + left = 0 + right = peak + while left <= right: + mid = (left + right) // 2 + cur = mountain_arr.get(mid) + if cur == target: + return mid + elif cur > target: + right = mid - 1 + else: + left = mid + 1 + + # 右边二分查找:递减数组 + left = peak + 1 + right = length - 1 + while left <= right: + mid = (left + right) // 2 + cur = mountain_arr.get(mid) + if cur == target: + return mid + elif cur > target: + left = mid + 1 + else: + right = mid - 1 + + return -1 +``` \ No newline at end of file From 88d9ea8370085a1a7498343d6026e4fcb218205f Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 2 May 2020 22:32:09 +0800 Subject: [PATCH 109/181] =?UTF-8?q?=F0=9F=90=B1(string):=203.=20=E6=97=A0?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E5=AD=97=E7=AC=A6=E7=9A=84=E6=9C=80=E9=95=BF?= =?UTF-8?q?=E5=AD=90=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/string/README.md | 51 +++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/string/README.md b/docs/data-structure/string/README.md index a5f3aba12..081798b06 100644 --- a/docs/data-structure/string/README.md +++ b/docs/data-structure/string/README.md @@ -76,7 +76,34 @@ if __name__ == '__main__': [原题链接](https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/) -### 思路 +### 解一:暴力求解 + +```python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + length = len(s) + ans = 0 + for i in range(length): + tmp = 1 + nums = dict() + nums[s[i]] = True + for j in range(i + 1, length): + c = s[j] + if c in nums: + # 已经存在 + break + else: + # 不存在,继续 + tmp += 1 + nums[c] = True + ans = max(ans, tmp) + return ans +``` + +- 时间复杂度:`O(n^2)` +- 空间复杂度:`O(m)` + +### 解二 - 用 hash 记录每个字符出现的位置 - 当前字符: @@ -108,6 +135,28 @@ class Solution(object): return max_length ``` +2020.05.02 复盘: + +```python +class Solution: + def lengthOfLongestSubstring(self, s: str) -> int: + ans = 0 + # 滑动窗口,左侧:start,右侧:i + start = 0 + length = len(s) + # 记录字符所在下标 + nums = dict() + for i in range(length): + cur_c = s[i] + # print(start) + if cur_c in nums: + if nums[cur_c] >= start: + start = nums[cur_c] + 1 + # 替换字符所在位置 + nums[cur_c] = i + ans = max(ans, i - start + 1) + return ans +``` ## 6. Z 字形变换 From 7d844f85c7bf9c36df8bee9de69de094872eefcc Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 3 May 2020 20:15:54 +0800 Subject: [PATCH 110/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=2053.=20?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=AD=90=E5=BA=8F=E5=92=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 73b695f8b..29005c07c 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -187,6 +187,20 @@ class Solution(object): return max_num ``` +2020.05.03 复盘: + +```python +class Solution: + def maxSubArray(self, nums: List[int]) -> int: + length = len(nums) + if length == 0: + return 0 + dp = [0 for _ in range(length)] + dp[0] = nums[0] + for i in range(1, length): + dp[i] = max(dp[i - 1] + nums[i], nums[i]) + return max(dp) +``` ## 55. 跳跃游戏 From 929b3c2152441bede35280712ca1b749c519bae1 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 4 May 2020 19:36:26 +0800 Subject: [PATCH 111/181] =?UTF-8?q?=F0=9F=90=B1(greedy):=2045.=20=E8=B7=B3?= =?UTF-8?q?=E8=B7=83=E6=B8=B8=E6=88=8F=20II=20=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/greedy/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/algorithm/greedy/README.md b/docs/algorithm/greedy/README.md index ee205d4f8..d530c91e3 100644 --- a/docs/algorithm/greedy/README.md +++ b/docs/algorithm/greedy/README.md @@ -74,6 +74,37 @@ class Solution(object): return res ``` +2020.05.04 复盘: + +```python +class Solution: + def jump(self, nums: List[int]) -> int: + # 每次跳到能跳到最远的位置 + ans = 0 + length = len(nums) + i = 0 + while i < length - 1: + num = nums[i] + max_index = i + max_jump = 0 + for j in range(1, num + 1): + # 跳跃到的位置 + next_i = i + j + if next_i >= length: + break + if next_i == length - 1: + # 已经跳到了最后一位 + max_index = next_i + break + if i + next_i + nums[next_i] > max_jump: + max_jump = i + next_i + nums[next_i] + max_index = next_i + # print(i, max_jump) + i = max_index + ans += 1 + return ans +``` + ## 122. 买卖股票的最佳时机 II [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/) From 341479accc7d04e6f66bc3359c7845ed9f0ceee0 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 6 May 2020 20:21:59 +0800 Subject: [PATCH 112/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20983.=20?= =?UTF-8?q?=E6=9C=80=E4=BD=8E=E7=A5=A8=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 29005c07c..2bc075951 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1508,6 +1508,35 @@ class Solution: return len(res) ``` +## 983. 最低票价 + +[原题链接](https://leetcode-cn.com/problems/minimum-cost-for-tickets/) + +### 解一:动态规划 + +从后往前进行动态规划,用 `dp[i]` 代表从第 `i` 天到最后一天需要的最低票价。 + +- 当 `i` 无需出行时,依据贪心法则:`dp[i] = dp[i + 1]`,即在第 `i` 天无需购票 +- 当 `i` 需要出行,`dp[i] = min(costs[j] + dp[i + j])`,`j` 的取值是 1/7/30。如果第 `i` 天出行,我们买了 `j` 天的票,那么后续 `j` 天都不需要购票事宜了,所以只要加上 `dp[i + j]` 的票价即可。 + +```python +class Solution: + def mincostTickets(self, days: List[int], costs: List[int]) -> int: + ans = 0 + dp = [0 for _ in range(400)] + for i in range(365, 0, -1): + if i in days: + # 需要出行 + min_dp = float('inf') + min_dp = min(costs[0] + dp[i + 1], costs[1] + dp[i + 7], costs[2] + dp[i + 30]) + dp[i] = min_dp + else: + # 不需要出行 + dp[i] = dp[i + 1] + # print(dp[20]) + return dp[1] +``` + ## 1137. 第 N 个泰波那契数 [原题链接](https://leetcode-cn.com/problems/n-th-tribonacci-number/) From 3cbb0dae05d80b73f0d777108d14468033244532 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 6 May 2020 22:58:38 +0800 Subject: [PATCH 113/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20983.=20?= =?UTF-8?q?=E6=9C=80=E4=BD=8E=E7=A5=A8=E4=BB=B7=20=E8=A1=A5=E5=85=85golang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 2bc075951..e61f43be9 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1519,6 +1519,10 @@ class Solution: - 当 `i` 无需出行时,依据贪心法则:`dp[i] = dp[i + 1]`,即在第 `i` 天无需购票 - 当 `i` 需要出行,`dp[i] = min(costs[j] + dp[i + j])`,`j` 的取值是 1/7/30。如果第 `i` 天出行,我们买了 `j` 天的票,那么后续 `j` 天都不需要购票事宜了,所以只要加上 `dp[i + j]` 的票价即可。 + + +#### **Python** + ```python class Solution: def mincostTickets(self, days: List[int], costs: List[int]) -> int: @@ -1537,6 +1541,42 @@ class Solution: return dp[1] ``` +#### **Go** + +```go +func mincostTickets(days []int, costs []int) int { + dp := make([]int, 400) + dayMap := make(map[int]int) + for _, day := range days { + dayMap[day] = 1 + } + for i := 365; i > 0; i-- { + // 从后向前动态规划 + if _, ok := dayMap[i]; ok { + // 该天出行 + cost0 := costs[0] + dp[i + 1] + cost1 := costs[1] + dp[i + 7] + cost2 := costs[2] + dp[i + 30] + dp[i] = getMin(getMin(cost0, cost1), cost2) + } else { + // 该天不出行 + dp[i] = dp[i + 1] + } + } + + return dp[1] +} + +func getMin(a int, b int) int { + if a < b { + return a + } + return b +} +``` + + + ## 1137. 第 N 个泰波那契数 [原题链接](https://leetcode-cn.com/problems/n-th-tribonacci-number/) From f8f3f644a8fbe3ee10226021857acde362b9303c Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 7 May 2020 22:28:15 +0800 Subject: [PATCH 114/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20572.=20=E5=8F=A6?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E6=A0=91=E7=9A=84=E5=AD=90=E6=A0=91=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=80=9D=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 6a60928d8..43849ba9c 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -1034,6 +1034,12 @@ func getMax(a int, b int) int { 与 [437](/tree/437.md) 递归思路类似。 +`t` 是否为 `s` 的子树,存在三种情况: + +- `t` 与 `s` 相同 +- `t` 是 `s` 的左子树 +- `t` 是 `s` 的右子树 + ```python class Solution(object): def isSubtree(self, s, t): @@ -1047,6 +1053,9 @@ class Solution(object): return self.isSubtreeWithRoot(s, t) or self.isSubtree(s.left, t) or self.isSubtree(s.right, t) def isSubtreeWithRoot(self, s, t): + """ + t 与 s 是否相同 + """ if s is None and t is None: return True if s is None or t is None: From aeab6a1f47d68c09843bc60d7036bd913fd97cd2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 7 May 2020 22:34:00 +0800 Subject: [PATCH 115/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20572.=20=E5=8F=A6?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E6=A0=91=E7=9A=84=E5=AD=90=E6=A0=91=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=20golang=20=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 43849ba9c..9860bd81e 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -1065,6 +1065,36 @@ class Solution(object): return self.isSubtreeWithRoot(s.left, t.left) and self.isSubtreeWithRoot(s.right, t.right) ``` +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func isSubtree(s *TreeNode, t *TreeNode) bool { + if s == nil { + return false + } + return isSubtree(s.Left, t) || isSubtree(s.Right, t) || isSubtreeWithRoot(s, t) +} + +func isSubtreeWithRoot(s *TreeNode, t *TreeNode) bool { + if s == nil && t == nil { + return true + } + if s == nil || t == nil { + return false + } + if s.Val != t.Val { + return false + } + return isSubtreeWithRoot(s.Left, t.Left) && isSubtreeWithRoot(s.Right, t.Right) +} +``` + ## 617. 合并二叉树 [原题链接](https://leetcode-cn.com/problems/merge-two-binary-trees/description/) From 0fa1ef9c1ca1c7d9eddfcd3cd0258f1946fe6ea1 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 9 May 2020 22:29:30 +0800 Subject: [PATCH 116/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=2069.=20x?= =?UTF-8?q?=20=E7=9A=84=E5=B9=B3=E6=96=B9=E6=A0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 8e3115273..a140bdb7c 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -219,6 +219,10 @@ class Solution(object): 二分查找,注意边界值的处理。 + + +#### **Python** + ```python class Solution(object): def mySqrt(self, x): @@ -245,6 +249,30 @@ class Solution(object): ``` +#### **Go** + +```go +func mySqrt(x int) int { + left := 0 + right := x + ans := 0 + for left <= right { + mid := (left + right) / 2 + // fmt.Println(mid) + if mid * mid <= x { + // 可能出现结果 + ans = mid + left = mid + 1 + } else { + right = mid - 1 + } + } + return ans +} +``` + + + ps:看评论有很秀的牛顿迭代法,有空研究下。 ## 74. 搜索二维矩阵 From f3e9651c470b94df2ce83511353a04a6938a0c19 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 10 May 2020 19:59:45 +0800 Subject: [PATCH 117/181] =?UTF-8?q?=F0=9F=90=B1(recursion):=20236.=20?= =?UTF-8?q?=E4=BA=8C=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E8=BF=91=E5=85=AC?= =?UTF-8?q?=E5=85=B1=E7=A5=96=E5=85=88=20=E8=A1=A5=E5=85=85=20golang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 9860bd81e..4981dcf7e 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -729,6 +729,41 @@ class Solution: return root ``` +#### **Go** + +```go +/** + * Definition for TreeNode. + * type TreeNode struct { + * Val int + * Left *ListNode + * Right *ListNode + * } + */ + func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode { + if root == nil || root == p || root == q { + return root + } + + // 寻找左子树 + left := lowestCommonAncestor(root.Left, p, q) + // 寻找右子树 + right := lowestCommonAncestor(root.Right, p, q) + + if left == nil && right == nil { + return nil + } + if left == nil { + return right + } + if right == nil { + return left + } + + return root +} +``` + ## 337. 打家劫舍 III From 9bf92a592d5c63e74cca37c4471c1efbcc627816 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 11 May 2020 22:51:26 +0800 Subject: [PATCH 118/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=2050.=20Po?= =?UTF-8?q?w(x,=20n)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index a140bdb7c..037cbcf7f 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -210,6 +210,39 @@ class Solution(object): return left ``` +## 50. Pow(x, n) + +[原题链接](https://leetcode-cn.com/problems/powx-n/) + +### 思路:二分 + +利用分治的思想,$x^2n$ 均可以写作 $x^n * x^n$。 + +递归: + +```go +func myPow(x float64, n int) float64 { + if n >= 0 { + return quickMul(x, n) + } + return 1 / quickMul(x, -n) +} + +func quickMul(x float64, n int) float64 { + if n == 0 { + return 1 + } + if n == 1 { + return x + } + y := quickMul(x, n / 2) + if n % 2 == 0 { + return y * y + } else { + return y * y * x + } +} +``` ## 69. x 的平方根 From b413871cf2f612782d21568986fa6e6fbe2712cb Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 12 May 2020 13:11:41 +0800 Subject: [PATCH 119/181] =?UTF-8?q?=F0=9F=90=B1(stack):=20155.=20=E6=9C=80?= =?UTF-8?q?=E5=B0=8F=E6=A0=88=20=E8=A1=A5=E5=85=85=20golang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index 1707ab760..68af07280 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -103,6 +103,10 @@ class Solution(object): - 每次入栈两个值:当前入栈元素、栈内最小值,保证栈内最小值永远在栈顶 + + +#### **Python** + ```python class MinStack(object): @@ -153,6 +157,82 @@ class MinStack(object): return self.stack[len(self.stack) - 1] ``` +#### **Go** + +```go +type MinStack struct { + Stack1 []int // 存放数据栈 + Stack2 []int // 递减栈 +} + + +/** initialize your data structure here. */ +func Constructor() MinStack { + var minStack MinStack + minStack.Stack1 = make([]int, 0) + minStack.Stack2 = make([]int, 0) + return minStack +} + + +func (this *MinStack) Push(x int) { + // 入栈 + this.Stack1 = append(this.Stack1, x) + // 维护递减栈 + stack2Length := len(this.Stack2) + if stack2Length == 0 { + this.Stack2 = append(this.Stack2, x) + } else { + // 与栈顶元素对比 + top := this.Stack2[stack2Length - 1] + if x < top { + this.Stack2 = append(this.Stack2, x) + } else { + this.Stack2 = append(this.Stack2, top) + } + } + // fmt.Println(this.Stack1) + // fmt.Println(this.Stack2) +} + + +func (this *MinStack) Pop() { + // 弹出元素 + stack1Length := len(this.Stack1) + this.Stack1 = this.Stack1[:stack1Length - 1] + stack2Length := len(this.Stack2) + this.Stack2 = this.Stack2[:stack2Length - 1] + // fmt.Println(this.Stack1) + // fmt.Println(this.Stack2) +} + + +func (this *MinStack) Top() int { + // 返回栈顶元素 + stack1Length := len(this.Stack1) + return this.Stack1[stack1Length - 1] +} + + +func (this *MinStack) GetMin() int { + // 返回 stack2 栈顶元素 + stack2Length := len(this.Stack2) + return this.Stack2[stack2Length - 1] +} + + +/** + * Your MinStack object will be instantiated and called as such: + * obj := Constructor(); + * obj.Push(x); + * obj.Pop(); + * param_3 := obj.Top(); + * param_4 := obj.GetMin(); + */ +``` + + + ## 173. 二叉搜索树迭代器 [原题链接](https://leetcode-cn.com/problems/binary-search-tree-iterator/) From 58e410718cbb7d0889e763ddfa8a9373ee480289 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 13 May 2020 21:08:37 +0800 Subject: [PATCH 120/181] =?UTF-8?q?=F0=9F=90=B1(backtrack):=2046.=20?= =?UTF-8?q?=E5=85=A8=E6=8E=92=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/backtrack/README.md | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/algorithm/backtrack/README.md b/docs/algorithm/backtrack/README.md index 8b717dd19..ef98f9757 100644 --- a/docs/algorithm/backtrack/README.md +++ b/docs/algorithm/backtrack/README.md @@ -52,4 +52,35 @@ class Solution(object): self.backtrack(tmp, i, combination + [num], nums, res) else: return +``` + +## 46. 全排列 + +[原题链接](https://leetcode-cn.com/problems/permutations/) + +### 思路:回溯 + +[参考题解](https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-xiang-jie-by-labuladong-2/) + +```python +class Solution: + def permute(self, nums: List[int]) -> List[List[int]]: + def track_back(nums, track): + if len(nums) == len(track): + ans.append(track[:]) + # 遍历集合 + for n in nums: + if n in track: + # 已经在决策树中 + continue + # 加入决策 + track.append(n) + track_back(nums, track) + # 回溯 + track.pop() + + ans = [] + track = [] + track_back(nums, track) + return ans ``` \ No newline at end of file From 8c5e25bdaf466c379a684e57cc60df6ba6041ecb Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 14 May 2020 08:07:08 +0800 Subject: [PATCH 121/181] =?UTF-8?q?=F0=9F=90=B1(bit):=20136.=20=E5=8F=AA?= =?UTF-8?q?=E5=87=BA=E7=8E=B0=E4=B8=80=E6=AC=A1=E7=9A=84=E6=95=B0=E5=AD=97?= =?UTF-8?q?=201.=20=E5=A4=8D=E7=9B=98=202.=20=E8=A1=A5=E5=85=85=20golang?= =?UTF-8?q?=20=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/bit/README.md | 18 ++++++++++++++++++ docs/data-structure/linked_list/README.md | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/bit/README.md b/docs/algorithm/bit/README.md index fc1fda219..80173d454 100644 --- a/docs/algorithm/bit/README.md +++ b/docs/algorithm/bit/README.md @@ -39,6 +39,10 @@ class Solution(object): - 相同为 0,不同为 1 - 0 与任何数异或都等于该数本身 + + +#### **Python** + ```python class Solution: def singleNumber(self, nums): @@ -52,6 +56,20 @@ class Solution: return a ``` +#### **Go** + +```go +func singleNumber(nums []int) int { + ans := 0 + for _, n := range nums { + ans ^= n + } + return ans +} +``` + + + ## 190. 颠倒二进制位 diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index a32191832..6c19dadf4 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -772,7 +772,7 @@ class Solution: class Solution: def reverseList(self, head: ListNode) -> ListNode: if head is None or head.next is None: - return head + return head # 取下一个节点 node = self.reverseList(head.next) From ac503f1122dd493f77495bc3ef1585b2ff7077c4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 15 May 2020 09:16:43 +0800 Subject: [PATCH 122/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20560.=20=E5=92=8C?= =?UTF-8?q?=E4=B8=BAK=E7=9A=84=E5=AD=90=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index af8bc021d..27b0fe82e 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -325,6 +325,83 @@ class Solution(object): return count ``` +## 560. 和为K的子数组 + +[原题链接](https://leetcode-cn.com/problems/subarray-sum-equals-k/) + +### 思路一:暴力破解 + +1. 固定左边界 +2. 枚举右边界 + +```go +func subarraySum(nums []int, k int) int { + length := len(nums) + ans := 0 + for left := 0; left < length; left++ { + s := 0 + for right := left; right < length; right++ { + s += nums[right] + if s == k { + ans += 1 + } + } + } + return ans +} +``` + +- 时间复杂度:$O(n^2)$ +- 空间复杂度:$O(1)$ + +### 思路二:前缀和 + 哈希 + +用 `pre[i]` 表示 `[0, ..., i]` 的和。 + +因此,`[j, ..., i]` 的和为 k 可以表示为:`pre[i] - pre[j - 1] == k`。 + +移项后:`pre[j - 1] == pre[i] - k`,因此,只要统计 `pre[i] - k` 即可。 + + + +#### **Python** + +```python +class Solution: + def subarraySum(self, nums: List[int], k: int) -> int: + ans, pre = 0, 0 + nums_dict = dict() + nums_dict[0] = 1 + for i in range(len(nums)): + pre += nums[i] + ans += nums_dict.get(pre - k, 0) + nums_dict[pre] = nums_dict.get(pre, 0) + 1 + return ans +``` + +#### **Go** + +```go +func subarraySum(nums []int, k int) int { + length := len(nums) + pre := 0 + ans := 0 + m := map[int]int{} + m[0] = 1 + for i := 0; i < length; i++ { + pre += nums[i] + if _, ok := m[pre - k]; ok { + ans += m[pre - k] + } + m[pre] += 1 + } + return ans +} +``` + + + + ## 575. 分糖果 [原题链接](https://leetcode-cn.com/problems/distribute-candies/) From 2652746c480af83a8b16881591afc75e6b8c9060 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sat, 16 May 2020 20:29:58 +0800 Subject: [PATCH 123/181] =?UTF-8?q?=F0=9F=90=B1(link):=2025.=20K=20?= =?UTF-8?q?=E4=B8=AA=E4=B8=80=E7=BB=84=E7=BF=BB=E8=BD=AC=E9=93=BE=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index a32191832..682f1a6d2 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -199,6 +199,73 @@ class Solution(object): return first.next ``` +## 25. K 个一组翻转链表 + +[原题链接](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/) + +### 思路 + +模拟过程。 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def reverseKGroup(self, head: ListNode, k: int) -> ListNode: + cur_idx = 0 + ans = ListNode(0) + + # 计算链表长度 + length = 0 + tmp = head + while tmp is not None: + length += 1 + tmp = tmp.next + + # 上一个节点 + pre = None + pre_range_tail, range_head = ans, ans + while head is not None and cur_idx + k <= length: + for i in range(k): + if i == 0: + # 记录头部指针 + range_head = head + if i == k - 1: + # 记录尾部节点 + range_tail = head + # 记录已遍历节点数量 + cur_idx += 1 + # 获取下一个节点 + next_node = head.next + # 反转链表,指向上一个节点 + head.next = pre + # 当前节点成为下一轮的「上一个节点」 + pre = head + # 继续遍历下一个节点 + head = next_node + # 前后两个链表相连 + pre_range_tail.next = range_tail + # print(ans) + pre_range_tail = range_head + # print(ans) + # 一轮结束,改变指针连接 + # range_head.next = head + # 一轮结束后,改变 pre 指向 + pre = None + + # 如果有剩余节点,继续连接 + range_head.next = head + + return ans.next +``` + +- 事件复杂度:O(n) +- 空间复杂度:O(1) + ## 61. 旋转链表 [原题链接](https://leetcode-cn.com/problems/rotate-list/solution/chuan-zhen-yin-xian-by-liweiwei1419/) From 0635cac2d5c98b8e4a07c8009f90dee1a4730c55 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Sun, 17 May 2020 20:41:18 +0800 Subject: [PATCH 124/181] =?UTF-8?q?=F0=9F=90=B1=20(graph):=20210.=20?= =?UTF-8?q?=E8=AF=BE=E7=A8=8B=E8=A1=A8=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/graph/README.md | 53 +++++++++++++++++++++++ docs/data-structure/linked_list/README.md | 4 -- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/docs/data-structure/graph/README.md b/docs/data-structure/graph/README.md index 3f26eca49..1ea43c32a 100644 --- a/docs/data-structure/graph/README.md +++ b/docs/data-structure/graph/README.md @@ -77,6 +77,59 @@ class Solution: return clone ``` +## 210. 课程表 II + +[原题链接](https://leetcode-cn.com/problems/course-schedule-ii/) + +### 思路 + +在图中找到循环。 + +```python +class Solution: + def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]: + length = len(prerequisites) + if length == 0: + return [i for i in range(numCourses)] + # n = len(prerequisites[0]) + + # 存储依赖关系 + degree = [0 for _ in range(numCourses)] + relations = dict() + for pre in prerequisites: + nxt = pre[0] + cur = pre[1] + # 依赖关系 + if cur not in relations: + relations[cur] = [nxt] + else: + relations[cur].append(nxt) + # nxt 课程的度 + 1 + degree[nxt] += 1 + + + # 入度为 0 的入队 + queue = [] + for i in range(numCourses): + if degree[i] == 0: + queue.append(i) + + # 遍历队列 + ans = [] + while len(queue) > 0: + first = queue[0] + del queue[0] + # if first not in ans: + ans.append(first) + # 获取下一批度为 0 的课程入队 + for course in relations.get(first, []): + degree[course] -= 1 + if degree[course] == 0: + queue.append(course) + + return ans if len(ans) == numCourses else [] +``` + ## 997. 找到小镇的法官 [原题链接](https://leetcode-cn.com/problems/find-the-town-judge) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 682f1a6d2..3151d70ce 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -132,9 +132,6 @@ class Solution(object): return head ``` - - - ## 21. 合并两个有序链表 [原题链接](https://leetcode-cn.com/problems/merge-two-sorted-lists/description/) @@ -167,7 +164,6 @@ class Solution(object): return head ``` - ## 24. 两两交换链表中的节点 ### 思路 From d587c603e8d8a9aac351454c1756257351189cfe Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 26 May 2020 23:36:28 +0800 Subject: [PATCH 125/181] =?UTF-8?q?=F0=9F=90=B1(array):=20287.=20=E5=AF=BB?= =?UTF-8?q?=E6=89=BE=E9=87=8D=E5=A4=8D=E6=95=B0=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E6=80=9D=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 2624637b1..10579c197 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1720,6 +1720,9 @@ class Solution: 将数组看成链表,val 是结点值也是下个节点的地址。因此这个问题就可以转换成判断链表有环,且找出入口节点。 +1. 如果有环:快慢指针在某一点相遇 +2. 此时再把其中一个指针移到起点,另一个指针移到相遇点(开始绕环跑),那么两个指针必然会在入口相遇 + ```python class Solution(object): def findDuplicate(self, nums): From 5ab82ad49eb039dc2e4e7640f89ff68e4c101cc4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 29 May 2020 09:53:53 +0800 Subject: [PATCH 126/181] =?UTF-8?q?=F0=9F=90=B1(stack):=20394.=20=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E8=A7=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index 68af07280..7b996dc96 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -956,6 +956,41 @@ class Solution: stack.append(node) ``` +## 394. 字符串解码 + +[原题链接](https://leetcode-cn.com/problems/decode-string/) + +### 解一:栈 + +1. 遇到非 `]` 元素先压入栈中 +2. 遇到 `]` 时,逐个弹出栈中元素,组成需要重复的字符串 `string`,直到遇到 `[` +3. 继续弹出 `[` 前的数字 `num` +4. 将 `string` 重复 `num` 压入栈中 +5. 重复上述过程,直到栈空 + +```python +class Solution: + def decodeString(self, s: str) -> str: + stack = [] + for c in s: + if c != ']': + stack.append(c) + else: + # 从栈中弹出 [] 内的元素与字母,并做乘法操作 + string = '' + while len(stack) > 0 and stack[-1] != '[': + string = stack.pop() + string + # 弹出 [ + stack.pop() + # 弹出重复数字 + num_string = '' + while len(stack) > 0 and stack[-1].isdigit(): + num_string = stack.pop() + num_string + num = int(num_string) + stack.append(string * num) + return ''.join(stack) +``` + ## 503. 下一个更大元素 II [原题链接](https://leetcode-cn.com/problems/next-greater-element-ii/submissions/) From f892af444b1e19bf67efcdbcc6bd48cfa675ed4b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 29 May 2020 10:55:09 +0800 Subject: [PATCH 127/181] =?UTF-8?q?=F0=9F=90=B1(stack):=20394.=20=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E8=A7=A3=E7=A0=81=20Python=20=E6=A0=88?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index 7b996dc96..bfac36b06 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -991,6 +991,38 @@ class Solution: return ''.join(stack) ``` +优化: + +1. 将数字记录在 `multi` 中,字母记录在 `res` 中 +2. 遇到 `[` 时,将 `[multi, res]` 入栈,并重置 `multi` 和 `res` +3. 遇到 `]` 时,从栈顶取元素 `[num, string]`,并计算 `res = string + num * res` + +```python +class Solution: + def decodeString(self, s: str) -> str: + stack = [] + # 存放字符串和数字 + res, multi = '', 0 + # ans = '' + for c in s: + if c == '[': + # 已经统计的 res 和 multi 入栈 + stack.append([res, multi]) + res, multi = '', 0 + elif c == ']': + # 出栈并计算结果 + string, num = stack.pop() + res = string + res * num + elif '0' <= c and c <= '9': + # 记录数字 + multi = 10 * multi + int(c) + else: + # 遇到字母 + res += c + # print(stack) + return res +``` + ## 503. 下一个更大元素 II [原题链接](https://leetcode-cn.com/problems/next-greater-element-ii/submissions/) From 2acbaebf7e1088f397d6c7625590b033dfb6f9b6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 2 Jun 2020 10:56:43 +0800 Subject: [PATCH 128/181] =?UTF-8?q?=F0=9F=90=B1(hash):=201.=20=E4=B8=A4?= =?UTF-8?q?=E6=95=B0=E4=B9=8B=E5=92=8C=201.=20=E8=A1=A5=E5=85=85=E6=9A=B4?= =?UTF-8?q?=E5=8A=9B=E8=A7=A3=E6=B3=95=202.=20=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 38 +++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 27b0fe82e..b292bbd80 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -2,7 +2,22 @@ [原题链接](https://leetcode-cn.com/problems/two-sum/submissions/) -### 解法一 +### 解法一:暴力 + +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + length = len(nums) + for i in range(length): + for j in range(i + 1, length): + if nums[i] + nums[j] == target: + return [i, j] +``` + +- 时间复杂度:$O(n^2)$ +- 空间复杂度:$O(1)$ + +### 解法二:一遍哈希 利用哈希表,时间复杂度 O(n),空间复杂度 O(n)。 @@ -34,15 +49,20 @@ class Solution(object): return res_list ``` -### 解法二 - -时间复杂度 O(nlogn),空间复杂度 O(1)。 - -- 排序 -- 二分查找 - - +2020.06.02 复盘: +```python +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + table = dict() + for i in range(len(nums)): + n = nums[i] + tmp = target - n + if tmp in table: + return [i, table[tmp]] + else: + table[n] = i +``` ## 128. 最长连续序列 From 21769823e3fb7b4f0649bfb950d9cb3f3f8cb26c Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 3 Jun 2020 16:54:05 +0800 Subject: [PATCH 129/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20205.=20=E5=90=8C?= =?UTF-8?q?=E6=9E=84=E5=AD=97=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 32 ++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index b292bbd80..ea89fdb27 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -133,6 +133,38 @@ class Solution(object): return max_length ``` +## 205. 同构字符串 + +[原题链接](https://leetcode-cn.com/problems/isomorphic-strings/) + +### 思路 + +双哈希表 + 双指针。 + +```python +class Solution: + def isIsomorphic(self, s: str, t: str) -> bool: + length1 = len(s) + length2 = len(t) + if length1 != length2: + return False + table1 = dict() + table2 = dict() + for i in range(length1): + if s[i] not in table1: + # 没有映射过 + table1[s[i]] = t[i] + # 判断是否进行了相同映射 + if t[i] in table2: + return False + table2[t[i]] = s[i] + else: + # 映射过了 + if t[i] != table1[s[i]]: + # 映射的字母不同 + return False + return True +``` ## 217. 存在重复元素 From 94fa529328cdfbffb02ef201af2fee810c4c52ff Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 12 Jun 2020 16:10:28 +0800 Subject: [PATCH 130/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20599.=20=E4=B8=A4?= =?UTF-8?q?=E4=B8=AA=E5=88=97=E8=A1=A8=E7=9A=84=E6=9C=80=E5=B0=8F=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E6=80=BB=E5=92=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index ea89fdb27..32356368c 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -663,6 +663,39 @@ class Solution(object): return max_length ``` +# 599. 两个列表的最小索引总和 + +[原题链接](https://leetcode-cn.com/problems/minimum-index-sum-of-two-lists/) + +## 解一:哈希表 + +```python +class Solution: + def findRestaurant(self, list1: List[str], list2: List[str]) -> List[str]: + table1 = dict() + table2 = dict() + length1 = len(list1) + length2 = len(list2) + for i in range(length1): + word = list1[i] + table1[word] = i + + min_index = float('inf') + for j in range(length2): + word = list2[j] + if word in table1: + table2[word] = j + table1.get(word) + if table2[word] < min_index: + min_index = table2[word] + + ans = [] + for k, v in table2.items(): + if v == min_index: + ans.append(k) + + return ans +``` + ## 705. 设计哈希集合 [原题链接](https://leetcode-cn.com/problems/design-hashset/) From 70114d509c775c87147bca8c0425a6fe9517f1c8 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 12 Jun 2020 17:48:29 +0800 Subject: [PATCH 131/181] =?UTF-8?q?=F0=9F=90=B1(sw):=20219.=20=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E9=87=8D=E5=A4=8D=E5=85=83=E7=B4=A0=20II=20=E5=A4=8D?= =?UTF-8?q?=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/sliding-window/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/algorithm/sliding-window/README.md b/docs/algorithm/sliding-window/README.md index fa0cab83a..2bf02ec47 100644 --- a/docs/algorithm/sliding-window/README.md +++ b/docs/algorithm/sliding-window/README.md @@ -31,6 +31,23 @@ class Solution(object): return False ``` +超时方法: + +```python +class Solution: + def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool: + length = len(nums) + i = 0 + while i < length: + j = i + 1 + while j < length and j <= i + k: + if nums[i] == nums[j]: + return True + j += 1 + i += 1 + return False +``` + ## 239. 滑动窗口最大值 [原题链接](https://leetcode-cn.com/problems/sliding-window-maximum/) From 15e8c783882fe1aaa512435196d61c94071b5bf5 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 30 Jun 2020 12:51:06 +0800 Subject: [PATCH 132/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20652.=20=E5=AF=BB?= =?UTF-8?q?=E6=89=BE=E9=87=8D=E5=A4=8D=E7=9A=84=E5=AD=90=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 32356368c..3b69d3ff7 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -696,6 +696,39 @@ class Solution: return ans ``` +## 652. 寻找重复的子树 + +[原题链接](https://leetcode-cn.com/problems/find-duplicate-subtrees/) + +### 解一:序列化,结果存放在哈希表中 + +```python +# 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 findDuplicateSubtrees(self, root: TreeNode) -> List[TreeNode]: + count = dict() + ans = list() + def collect(node): + if node is None: + return '#' + left_serial = collect(node.left) + right_serial = collect(node.right) + serial = "{},{},{}".format(node.val, left_serial, right_serial) + count[serial] = count.get(serial, 0) + 1 + if count[serial] == 2: + ans.append(node) + return serial + + collect(root) + return ans +``` + ## 705. 设计哈希集合 [原题链接](https://leetcode-cn.com/problems/design-hashset/) From 1b69f4105e260e99a0bb63a401e91820903fd47d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 8 Jul 2020 10:46:14 +0800 Subject: [PATCH 133/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20153.=20?= =?UTF-8?q?=E5=AF=BB=E6=89=BE=E6=97=8B=E8=BD=AC=E6=8E=92=E5=BA=8F=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E4=B8=AD=E7=9A=84=E6=9C=80=E5=B0=8F=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 037cbcf7f..01dd38494 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -389,6 +389,28 @@ func searchMatrix(matrix [][]int, target int) bool { } ``` +## 153. 寻找旋转排序数组中的最小值 + +[原题链接](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) + +### 思路 + +```python +class Solution: + def findMin(self, nums: List[int]) -> int: + left = 0 + right = len(nums) - 1 + while left < right: + mid = (left + right) // 2 + if nums[mid] < nums[right]: + # mid 可能是最小值 + right = mid + else: + # 最小值在 mid 右侧 + left = mid + 1 + return nums[left] +``` + ## 162. 寻找峰值 [原题链接](https://leetcode-cn.com/problems/find-peak-element/) From 718c571f62850f28bca1b19bac29988ec8a3904d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 8 Jul 2020 12:38:15 +0800 Subject: [PATCH 134/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=2034.=20?= =?UTF-8?q?=E5=9C=A8=E6=8E=92=E5=BA=8F=E6=95=B0=E7=BB=84=E4=B8=AD=E6=9F=A5?= =?UTF-8?q?=E6=89=BE=E5=85=83=E7=B4=A0=E7=9A=84=E7=AC=AC=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=92=8C=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AA=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充解法二 --- .../research/binary-search/README.md | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 01dd38494..87c693ad9 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -121,7 +121,7 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/) -### 思路 +### 解一:二分 + 线性查找 先使用二分查找法找到 target 值,然后从找到 target 值的位置往左右两侧延伸,直到寻找到两侧的边界值。 @@ -160,6 +160,43 @@ class Solution(object): return res ``` +### 解二:两侧都使用二分查找 + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + res = [-1, -1] + if len(nums) == 0: + return res + + left = 0 + right = len(nums) - 1 + while left < right: + mid = (left + right) // 2 + if nums[mid] < target: + left = mid + 1 + elif nums[mid] > target: + right = mid - 1 + else: + right = mid + if nums[left] == target: + res[0] = left + + left = 0 + right = len(nums) + while left < right: + mid = (left + right) // 2 + if nums[mid] < target: + left = mid + 1 + elif nums[mid] > target: + right = mid + else: + left = mid + 1 + if nums[left - 1] == target: + res[1] = left - 1 + + return res +``` ## 35. 搜索插入位置 From e6f0d9641d4dfcaad242803f305cb474154d63ec Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 10 Jul 2020 12:47:48 +0800 Subject: [PATCH 135/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=2034.=20?= =?UTF-8?q?=E5=9C=A8=E6=8E=92=E5=BA=8F=E6=95=B0=E7=BB=84=E4=B8=AD=E6=9F=A5?= =?UTF-8?q?=E6=89=BE=E5=85=83=E7=B4=A0=E7=9A=84=E7=AC=AC=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=92=8C=E6=9C=80=E5=90=8E=E4=B8=80=E4=B8=AA=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/research/binary-search/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 87c693ad9..b2b3ca6fd 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -183,7 +183,7 @@ class Solution: res[0] = left left = 0 - right = len(nums) + right = len(nums) # 只有一个数的时候需要取到右边界 while left < right: mid = (left + right) // 2 if nums[mid] < target: From f5546420151eefa6c03c35c462061340bee8323d Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 13 Jul 2020 16:11:29 +0800 Subject: [PATCH 136/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20658.=20?= =?UTF-8?q?=E6=89=BE=E5=88=B0=20K=20=E4=B8=AA=E6=9C=80=E6=8E=A5=E8=BF=91?= =?UTF-8?q?=E7=9A=84=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index b2b3ca6fd..b6715cf52 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -840,6 +840,44 @@ func getMax(a int, b int) int { +## 658. 找到 K 个最接近的元素 + +[原题链接](https://leetcode-cn.com/problems/find-k-closest-elements/) + +### 解一:二分查找 + +在 `[0, length - k]` 区间查找最终答案的最左边界,对比方法是比较 `arr[mid] - x`(记作 `diff_left`) 和 `arr[mid + k] - x` (记作 `diff_right`)的大小: + +1. `diff_left < diff_right`:说明此时 `arr[mid]` 距离 `x` 更近些,可以继续向左边扩展(但保留此 `mid` 位置),`right = mid` +2. `diff_left == diff_right`:此时两处一样近,可以继续向左边扩展(但保留此 `mid` 位置),`right = mid` +3. `diff_left > diff_right`:说明 `arr[mid + k]` 距离 `x` 更近些,向右边扩展,`left = mid + 1` + +```python +class Solution: + def findClosestElements(self, arr: List[int], k: int, x: int) -> List[int]: + length = len(arr) + left = 0 + right = length - k + # 找到距离 k 最近的左边界 + while left < right: + mid = (left + right) // 2 + left_diff = x - arr[mid] + right_diff = arr[mid + k] - x + print(left, right, left_diff, right_diff) + if left_diff < right_diff: + # 左边离 x 比较近,区间可以继续向左扩张 + right = mid + # pass + elif left_diff == right_diff: + # 两边一样近,可以往左(取小值) + right = mid + else: + # 右边离 x 比较近,区间向右扩张 + left = mid + 1 + + return arr[left:left + k] +``` + ## 1095. 山脉数组中查找目标值 [原题链接](https://leetcode-cn.com/problems/find-in-mountain-array/) From 10d99074e099b5d3210dcfff7d2a33d3ca61d656 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 15 Jul 2020 10:17:30 +0800 Subject: [PATCH 137/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=204.=20?= =?UTF-8?q?=E5=AF=BB=E6=89=BE=E4=B8=A4=E4=B8=AA=E6=9C=89=E5=BA=8F=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E7=9A=84=E4=B8=AD=E4=BD=8D=E6=95=B0=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E4=BA=8C=E5=88=86=E9=80=92=E5=BD=92=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index b6715cf52..cafecb45b 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -116,6 +116,43 @@ class Solution(object): return (c1 + c2) / 2.0 ``` +二分法递归写法: + +思想:转变为求**第 K 小数**。 + +Tips:因为长度要分奇偶讨论,因此直接取 `(m + n + 1) / 2` 与 `(m + n + 2) / 2` 的平均值,奇偶就一样了。 + +```python +class Solution: + def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: + def findKthElement(arr1, arr2, k): + # 默认 2 比 1 长 + length1, length2 = len(arr1), len(arr2) + if length1 > length2: + return findKthElement(arr2, arr1, k) + + # 如果 arr1 没有元素,直接返回 arr2 的第 k 小 + if length1 == 0: + return arr2[k - 1] + + # 等于 1 时单独处理 + if k == 1: + return min(arr1[0], arr2[0]) + + # 两者都有元素,对比 k/2 位置,但不超过数组长度 + mid1 = min(k//2, length1) - 1 + mid2 = min(k//2, length2) - 1 + if arr1[mid1] > arr2[mid2]: + # 删除 arr 的部分 + return findKthElement(arr1, arr2[mid2+1:], k - mid2 - 1) + else: + return findKthElement(arr1[mid1+1:], arr2, k - mid1 - 1) + + l1, l2 = len(nums1), len(nums2) + left, right = (l1 + l2 + 1)//2, (l1 + l2 + 2)//2 + return (findKthElement(nums1, nums2, left) + findKthElement(nums1, nums2, right)) / 2 +``` + ## 34. 在排序数组中查找元素的第一个和最后一个位置 From 37cdbc382353da99b26385f3cde00b0d66ebecd8 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 16 Jul 2020 14:55:55 +0800 Subject: [PATCH 138/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20367.=20?= =?UTF-8?q?=E6=9C=89=E6=95=88=E7=9A=84=E5=AE=8C=E5=85=A8=E5=B9=B3=E6=96=B9?= =?UTF-8?q?=E6=95=B0=20=E8=A1=A5=E5=85=85=E7=BC=A9=E5=B0=8F=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index cafecb45b..9b871564e 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -649,6 +649,28 @@ class Solution: return left * left == num ``` +缩小查找范围:`right = num / 2` + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + if num < 2: + return True + left = 1 + right = num // 2 + + while left <= right: + mid = (left + right) // 2 + tmp = mid * mid + if tmp == num: + return True + elif tmp < num: + left = mid + 1 + else: + right = mid - 1 + return False +``` + #### **Go** ```go From 49650162e85cca8c0988fd7834822dc410050af5 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 20 Jul 2020 14:56:54 +0800 Subject: [PATCH 139/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20744.=20?= =?UTF-8?q?=E5=AF=BB=E6=89=BE=E6=AF=94=E7=9B=AE=E6=A0=87=E5=AD=97=E6=AF=8D?= =?UTF-8?q?=E5=A4=A7=E7=9A=84=E6=9C=80=E5=B0=8F=E5=AD=97=E6=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 9b871564e..62075dde2 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -937,6 +937,62 @@ class Solution: return arr[left:left + k] ``` +## 744. 寻找比目标字母大的最小字母 + +[原题链接](https://leetcode-cn.com/problems/find-smallest-letter-greater-than-target/) + +### 思路 + +给你一个**排序后的字符列表**,和一个**目标字母**,要查找比这个字母**大**的**最小字母**,很容易就想到**二分查找**。 + +因为「在比较时,字母是依序循环出现的」,所以我们可以先处理特殊情况:**当我们要查找的字母大于等于列表的最后一个字母时,直接返回列表第一字母**。 + +下面说说二分查找。 + +首先定义好模板: + +```python +left = 0 +right = length + +while left < right: + mid = (left + rigt) // 2 + letter = letters[mid] + # 其他逻辑…… +``` + +此处我们取到的中间值 `letter` 与 `target` 存在三种大小关系: + +- `letter == target`:两者相等。此时说明我们已经找到了目标字母,但我们要找的是比目标字母大的最小字母,所以我们需要把查找范围变成 `mid` 右侧,继续向更大的字母范围处查找,即 `left = mid + 1` +- `letter < target`:当前字母小于目标字母,说明目标值在 `mid` 右侧,同上 `left = mid + 1` +- `letter > target`:当前字母大于目标字母。此时当前字母可能就是我们要找的最终答案了,但也有可能答案在左侧范围,所以 `right = mid`,**保留当前字母位置**,且继续向左侧查找 + +### 具体实现 + +```python +class Solution: + def nextGreatestLetter(self, letters: List[str], target: str) -> str: + length = len(letters) + # 循环的特殊情况 + if letters[length - 1] <= target: + return letters[0] + left = 0 + right = length - 1 + while left < right: + mid = (left + right) // 2 + letter = letters[mid] + if letter == target: + # 等于目标值,往右找 + left = mid + 1 + elif letter < target: + # 比目标值小,往右找 + left = mid + 1 + else: + # 比目标值大,可能就是要找的数! + right = mid + return letters[left] +``` + ## 1095. 山脉数组中查找目标值 [原题链接](https://leetcode-cn.com/problems/find-in-mountain-array/) From fc0e77c1ce3c25b8fe4c14b7dffd4d78847f796f Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 22 Jul 2020 17:53:25 +0800 Subject: [PATCH 140/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20154.=20?= =?UTF-8?q?=E5=AF=BB=E6=89=BE=E6=97=8B=E8=BD=AC=E6=8E=92=E5=BA=8F=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E4=B8=AD=E7=9A=84=E6=9C=80=E5=B0=8F=E5=80=BC=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 62075dde2..8bb6bbf5a 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -485,6 +485,33 @@ class Solution: return nums[left] ``` +## 154. 寻找旋转排序数组中的最小值 II + +[原题链接](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array-ii/) + +## 思路 + +同 153,重点在于如何处理相等情况。 + +```python +class Solution: + def findMin(self, nums: List[int]) -> int: + length = len(nums) + left = 0 + right = length - 1 + while left < right: + mid = (left + right) // 2 + if nums[mid] < nums[right]: + # 在左侧 + right = mid + elif nums[mid] > nums[right]: + # 在右侧 + left = mid + 1 + else: + right -= 1 + return nums[left] +``` + ## 162. 寻找峰值 [原题链接](https://leetcode-cn.com/problems/find-peak-element/) From c29ceee05de17244c7ef38b442c651acdb7f264a Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 23 Jul 2020 10:49:19 +0800 Subject: [PATCH 141/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E9=A2=98=E8=A7=A3=E4=B8=8E=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 65 +++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index 3b69d3ff7..e064be209 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -207,15 +207,44 @@ class Solution: return True ``` +## 349. 两个数组的交集 + +[原题链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/) + +### 解一:内置函数 + +```python +class Solution: + def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]: + return list(set(nums1) & set(nums2)) +``` + +#### 复杂度 + +- 时间复杂度:将数组转为 `set` 的复杂度为 `O(n)`,转化两个数组时间复杂度 `O(m) + O(n)` + - 平均情况下:`O(m + n)` + - 最坏情况下:`O(m * n)` +- 空间复杂度:最坏情况 `O(m + n)`(数组元素都不同的情况) + +### 解二:排序 + 双指针 + +先对二者排序,使用双指针滑动查找。 + +### 解三:排序 + 二分查找 + +一个数组排序(短数组?),另一数组内的元素使用二分查找。 ## 350. 两个数组的交集 II [原题链接](https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/) -### 解法一 +### 解法一:哈希 使用 hash 表的方式。 +- 遍历较短数组,将数据存储在哈希表中,存储的值为数字出现的次数 +- 遍历较长数组,查询数据是否在哈希表出现过 + 空间复杂度 `O(n)`,时间复杂度 `O(n)`。 ```python @@ -243,10 +272,42 @@ class Solution(object): return res ``` -### 解法二 +#### 复杂度 + +- 时间复杂度:`O(m + n)` +- 空间复杂度:`O(min(m, n))`(不会超过短数组长度) + +### 解法二:排序 + 双指针 排序 + 双指针,不需要额外空间。 +```python +class Solution: + def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: + nums1.sort() + nums2.sort() + i = 0 + j = 0 + length1 = len(nums1) + length2 = len(nums2) + res = [] + while i < length1 and j < length2: + if nums1[i] == nums2[j]: + res.append(nums1[i]) + i += 1 + j += 1 + elif nums1[i] < nums2[j]: + i += 1 + else: + j += 1 + return res +``` + +#### 复杂度 + +- 事件复杂度:`mO(logm) + nO(logn)` +- 空间复杂度:`O(len(res))`(结果答案长度) + ## 355. 设计推特 [原题链接](https://leetcode-cn.com/problems/design-twitter/) From fad7de807c1947a9c8403dcb0c6982a0c805cea4 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 23 Jul 2020 14:33:28 +0800 Subject: [PATCH 142/181] =?UTF-8?q?=F0=9F=90=B1(array):=20167.=20=E4=B8=A4?= =?UTF-8?q?=E6=95=B0=E4=B9=8B=E5=92=8C=20II=20-=20=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E6=9C=89=E5=BA=8F=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 10579c197..608964f5c 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1255,6 +1255,35 @@ class Solution(object): return [i + 1, j + 1] ``` +- 时间复杂度 `O(n)` +- 空间复杂度 `O(1)` + +### 解二:二分查找 + +```python +class Solution: + def twoSum(self, numbers: List[int], target: int) -> List[int]: + length = len(numbers) + i = 0 + while i < length: + j = i + 1 + target_j = target - numbers[i] + left = j + right = length - 1 + while left <= right: + mid = (left + right) // 2 + if numbers[mid] == target_j: + return [i + 1, mid + 1] + elif numbers[mid] < target_j: + left = mid + 1 + else: + right = mid - 1 + i += 1 +``` + +- 时间复杂度 `O(nlogn)` +- 空间复杂度:`O(1)` + ## 169. 多数元素 [原题链接](https://leetcode-cn.com/problems/majority-element/) From 45b509fd449376ea1dbfcf2bc01c00db2fe206aa Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 24 Jul 2020 10:52:46 +0800 Subject: [PATCH 143/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=201025.=20?= =?UTF-8?q?=E9=99=A4=E6=95=B0=E5=8D=9A=E5=BC=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index e61f43be9..bc4e3a1e3 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1655,4 +1655,32 @@ class Solution: return self.tribonacci(n - 3) + self.tribonacci(n - 2) + self.tribonacci(n - 1) ``` - \ No newline at end of file + + +## 1025. 除数博弈 + +[原题链接](https://leetcode-cn.com/problems/divisor-game/) + +### 思路 + +当 `N = 1` 时Alice 会输,当 `N = 2` 时 Alice 会赢…… + +以 `dp(N)` 代表 `N` 时先手的输赢。 + +在 `N` 中找到约数 `j`,若 `dp(N - j) == False`(Bob 输) 则说明 Alice 获胜。 + +```python +class Solution: + def divisorGame(self, N: int) -> bool: + dp = [False for _ in range(N + 1)] + if N <= 1: + return False + dp[1] = False + dp[2] = True + for i in range(3, N + 1): + for j in range(1, i // 2): + # i 的约数是否存在 dp[j] 为 False,此时 Alice 获胜 + if i % j == 0 and dp[i - j] is False: + dp[i] = True + return dp[N] +``` \ No newline at end of file From 173b494224a9b8daa82fcf4cbc29b0367a071e7f Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 24 Jul 2020 14:58:32 +0800 Subject: [PATCH 144/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20410.=20?= =?UTF-8?q?=E5=88=86=E5=89=B2=E6=95=B0=E7=BB=84=E7=9A=84=E6=9C=80=E5=A4=A7?= =?UTF-8?q?=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 8bb6bbf5a..7d4180e18 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -803,6 +803,50 @@ public class Solution extends GuessGame { +## 410. 分割数组的最大值 + +[原题链接](https://leetcode-cn.com/problems/split-array-largest-sum/) + +### 解一:二分查找 + +想不到的神思路:对比分割次数,不断缩小最终答案范围。 + +在不考虑 `m` 的情况下,我们可知道最终的答案一定落在 `[max(nums), sum(nums)]` 区间内。因此,我们可以使用二分查找,在该范围内不断缩小最终答案的范围。 + +设 `left = max(nums)`,`right = sum(nums)`,`mid = (left + right) // 2`,此时假设 `mid` 是已求出的答案,即所谓「最大值」。我们可以用 `mid` 反推数组需要分割的数量 `cnt`: + +- `cnt <= m`:分割的数量过少,说明 `mid` 太大,`right = mid` +- `cnt > m`:分割数量过多,说明 `mid` 太小,`left = mid + 1` + +```python +class Solution: + def splitArray(self, nums: List[int], m: int) -> int: + # 最终结果范围:[max(nums), sum(nums)] + left = max(nums) + right = sum(nums) + while left < right: + mid = (left + right) // 2 + # 根据此 mid 反求划分数量 + cnt, total = 1, 0 + for num in nums: + total += num + if total > mid: + # 划分 + cnt += 1 + total = num + + if cnt < m: + # 划分少了,mid 太大,往左边找 + right = mid + elif cnt == m: + right = mid + else: + # 划分多了,mid 太小,往右边找 + left = mid + 1 + + return left +``` + ## 475. 供暖器 [原题链接](https://leetcode-cn.com/problems/heaters/) From 106ed64bf24616ab1d5a541bba28d0c4a319c726 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 28 Jul 2020 16:00:30 +0800 Subject: [PATCH 145/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=20719.=20?= =?UTF-8?q?=E6=89=BE=E5=87=BA=E7=AC=AC=20k=20=E5=B0=8F=E7=9A=84=E8=B7=9D?= =?UTF-8?q?=E7=A6=BB=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 7d4180e18..b7ec41e97 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -1008,6 +1008,45 @@ class Solution: return arr[left:left + k] ``` +## 719. 找出第 k 小的距离对 + +[原题链接](https://leetcode-cn.com/problems/find-k-th-smallest-pair-distance/) + +### 解一:二分查找 + 双指针 + +- k 值落在 `[0, max(nums) - min(nums)]` 中,此为二分查找范围 +- 以此范围内的值查找小于该值的距离对数量 + +```python +class Solution: + def smallestDistancePair(self, nums: List[int], k: int) -> int: + nums.sort() + + def get_mid_count(target): + # 双指针 + i, count = 0, 0 + for j in range(1, len(nums)): + while nums[j] - nums[i] > target: + i += 1 + count += j - i + return count + + # 第 k 小距离在 [left, right] 之间 + left = 0 + right = nums[-1] - nums[0] + while left < right: + mid = (left + right) // 2 + # 计算小于等于 mid 的数量 + count = get_mid_count(mid) + if count >= k: + # 如果数量大于 k,说明 mid 大了或就是结果 + right = mid + else: + # 如果数量小于 k,说明 mid 小了 + left = mid + 1 + return left +``` + ## 744. 寻找比目标字母大的最小字母 [原题链接](https://leetcode-cn.com/problems/find-smallest-letter-greater-than-target/) From 9e9cbb72c5233772abb936a5f053e7567e7fbea6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 29 Jul 2020 15:38:43 +0800 Subject: [PATCH 146/181] =?UTF-8?q?=F0=9F=90=B1(string):=20344.=20?= =?UTF-8?q?=E5=8F=8D=E8=BD=AC=E5=AD=97=E7=AC=A6=E4=B8=B2=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E9=80=92=E5=BD=92=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/string/README.md | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/string/README.md b/docs/data-structure/string/README.md index 081798b06..ef82c62bf 100644 --- a/docs/data-structure/string/README.md +++ b/docs/data-structure/string/README.md @@ -1140,7 +1140,7 @@ for key, value in c_dict.items(): [原题链接](https://leetcode-cn.com/problems/reverse-string/) -### 思路 +### 解一:双指针 头尾双指针,不停交换并往中间靠拢。 @@ -1162,6 +1162,48 @@ class Solution(object): j = j - 1 ``` +### 解二:递归 + + + +#### **Python** + +```python +class Solution: + def reverseString(self, s: List[str]) -> None: + """ + Do not return anything, modify s in-place instead. + """ + def helper(left, right): + if left >= right: + return + s[left], s[right] = s[right], s[left] + helper(left + 1, right - 1) + + helper(0, len(s) - 1) +``` + +#### **Go** + +```go +func reverseString(s []byte) { + helper(0, len(s) - 1, s) +} + +func helper(left int, right int, s []byte) { + if left >= right { + return + } + + tmp := s[left] + s[left] = s[right] + s[right] = tmp + helper(left + 1, right - 1, s) +} +``` + + + ## 345. 反转字符串中的元音字母 From c0757932d807ae9cd9ccc4b31c6ed6b29dc31e55 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 29 Jul 2020 17:17:28 +0800 Subject: [PATCH 147/181] =?UTF-8?q?=F0=9F=90=B1(link):=2024.=20=E4=B8=A4?= =?UTF-8?q?=E4=B8=A4=E4=BA=A4=E6=8D=A2=E9=93=BE=E8=A1=A8=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9=20=E8=A1=A5=E5=85=85=E9=80=92=E5=BD=92?= =?UTF-8?q?=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/linked_list/README.md | 54 +++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 3151d70ce..190e92ca4 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -166,14 +166,12 @@ class Solution(object): ## 24. 两两交换链表中的节点 -### 思路 +### 解一:迭代 - 为方便统一化创建空节点 `cur` - 交换呗,没啥好说 - 注意返回头节点 -### Python - ```python class Solution(object): def swapPairs(self, head): @@ -195,6 +193,56 @@ class Solution(object): return first.next ``` +### 解二:递归 + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def swapPairs(self, head: ListNode) -> ListNode: + def helper(node, pre): + if node is None or node.next is None: + return + next_node = node.next + # 指针交换 + node.next = next_node.next + next_node.next = node + pre.next = next_node + helper(node.next, node) + + ans = ListNode(0) + ans.next = head + helper(head, ans) + return ans.next +``` + +优雅递归: + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def swapPairs(self, head: ListNode) -> ListNode: + if head is None or head.next is None: + return head + + first_node = head + second_node = head.next + + first_node.next = self.swapPairs(second_node.next) + second_node.next = first_node + + return second_node +``` + ## 25. K 个一组翻转链表 [原题链接](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/) From 2581b7f5b3525b0d6a0107f0211ccb98c696735e Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 30 Jul 2020 15:28:53 +0800 Subject: [PATCH 148/181] =?UTF-8?q?=F0=9F=90=B1(link):=2024.=20=E4=B8=A4?= =?UTF-8?q?=E4=B8=A4=E4=BA=A4=E6=8D=A2=E9=93=BE=E8=A1=A8=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 go 语言 --- docs/data-structure/linked_list/README.md | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/data-structure/linked_list/README.md b/docs/data-structure/linked_list/README.md index 190e92ca4..b3f5e70b1 100644 --- a/docs/data-structure/linked_list/README.md +++ b/docs/data-structure/linked_list/README.md @@ -222,6 +222,10 @@ class Solution: 优雅递归: + + +#### **Python** + ```python # Definition for singly-linked list. # class ListNode: @@ -243,6 +247,33 @@ class Solution: return second_node ``` +#### **Go** + +```go +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ +func swapPairs(head *ListNode) *ListNode { + if head == nil || head.Next == nil { + return head + } + + firstNode := head + secondNode := head.Next + + firstNode.Next = swapPairs(secondNode.Next) + secondNode.Next = firstNode + + return secondNode +} +``` + + + ## 25. K 个一组翻转链表 [原题链接](https://leetcode-cn.com/problems/reverse-nodes-in-k-group/) From 978f347c12e2acbfca4a7fe37729d96de848266b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 30 Jul 2020 17:50:42 +0800 Subject: [PATCH 149/181] =?UTF-8?q?=F0=9F=90=B1(array):=20119.=20=E6=9D=A8?= =?UTF-8?q?=E8=BE=89=E4=B8=89=E8=A7=92=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充递归 --- docs/data-structure/array/README.md | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 608964f5c..7db7342ea 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1087,6 +1087,27 @@ class Solution(object): return res ``` +优化: + +```go +func generate(numRows int) [][]int { + var res [][]int = make([][]int, numRows) + + for i := 0; i < numRows; i++ { + res[i] = make([]int, i + 1) + for j := 0; j < i + 1; j++ { + if j == 0 || j == i { + res[i][j] = 1 + } else { + res[i][j] = res[i - 1][j - 1] + res[i - 1][j] + } + } + } + + return res +} +``` + ## 119. 杨辉三角 II @@ -1124,6 +1145,32 @@ class Solution(object): return cur ``` +### 解二:递归 + +```python +class Solution: + def generate(self, numRows: int) -> List[List[int]]: + ans = [] + # 递归:输入上一行,返回下一行 + def helper(pre): + length = len(pre) + if length == numRows: + return + if length == 0: + nxt = [1] + elif length == 1: + nxt = [1, 1] + else: + nxt = [1] + for i in range(length - 1): + nxt.append(pre[i] + pre[i + 1]) + nxt.append(1) + ans.append(nxt) + helper(nxt) + + helper([]) + return ans +``` ## 121. 买卖股票的最佳时机 From 2a49187916e150a3792ee1284c8722d8d26bf7c3 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 30 Jul 2020 18:04:29 +0800 Subject: [PATCH 150/181] =?UTF-8?q?=F0=9F=90=B1(array):=20118.=20=E6=9D=A8?= =?UTF-8?q?=E8=BE=89=E4=B8=89=E8=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充 python 题解 --- docs/data-structure/array/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 7db7342ea..35783d3d7 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1089,6 +1089,23 @@ class Solution(object): 优化: +#### **Python** + +```python +class Solution: + def generate(self, numRows: int) -> List[List[int]]: + ans = [] + for i in range(numRows): + tmp = [1 for _ in range(i + 1)] + for j in range(1, i): + tmp[j] = ans[i - 1][j - 1] + ans[i - 1][j] + ans.append(tmp) + + return ans +``` + +#### **Go** + ```go func generate(numRows int) [][]int { var res [][]int = make([][]int, numRows) From 484dd697de8a5c7c4791db253a3e315015d2b095 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 4 Aug 2020 16:14:42 +0800 Subject: [PATCH 151/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=2050.=20Po?= =?UTF-8?q?w(x,=20n)=20=E8=A1=A5=E5=85=85=20Python=20=E9=A2=98=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index b7ec41e97..7e244be43 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -288,12 +288,35 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/powx-n/) -### 思路:二分 +### 思路:快速幂 利用分治的思想,$x^2n$ 均可以写作 $x^n * x^n$。 递归: + + +#### **Python** + +```python +class Solution: + def myPow(self, x: float, n: int) -> float: + def fast_pow(x, n): + if n == 0: + return 1 + + fast_res = fast_pow(x, n//2) + if n % 2 == 0: + return fast_res * fast_res + else: + return fast_res * fast_res * x + + res = fast_pow(x, abs(n)) + return res if n > 0 else 1/res +``` + +#### **Go** + ```go func myPow(x float64, n int) float64 { if n >= 0 { @@ -318,6 +341,8 @@ func quickMul(x float64, n int) float64 { } ``` + + ## 69. x 的平方根 [原题链接](https://leetcode-cn.com/problems/sqrtx/comments/) From 9dff793ad66e87e01ae1b51986808f4e21f1c635 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 14 Aug 2020 12:38:27 +0800 Subject: [PATCH 152/181] =?UTF-8?q?=F0=9F=90=B1(array):=20283.=20=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E9=9B=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充优化解法 --- docs/data-structure/array/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 35783d3d7..158f5acce 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1754,6 +1754,25 @@ class Solution: j = j + 1 ``` +优化:让 `j` 跳过 0。 + +```python +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + i = 0 + for j in range(len(nums)): + if nums[j] == 0: + continue + else: + nums[i], nums[j] = nums[j], nums[i] + i += 1 + + return nums +``` + ## 287. 寻找重复数 From 42774152c0a0806f23f64746758c860e414b7cb9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 14 Aug 2020 14:23:33 +0800 Subject: [PATCH 153/181] =?UTF-8?q?=F0=9F=90=B1(array):=2027.=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E5=85=83=E7=B4=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充优化代码 --- docs/data-structure/array/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 158f5acce..be8a348c8 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -371,6 +371,20 @@ class Solution: return res ``` +优化: + +```python +class Solution: + def removeElement(self, nums: List[int], val: int) -> int: + i = 0 + for j in range(len(nums)): + if nums[j] == val: + continue + nums[i], nums[j] = nums[j], nums[i] + i += 1 + return i +``` + #### **Go** ```go From 320e6d32db74e01d02dee446f3b17514a0f89eea Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 14 Aug 2020 14:49:10 +0800 Subject: [PATCH 154/181] =?UTF-8?q?=F0=9F=90=B1(array):=2026.=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8E=92=E5=BA=8F=E6=95=B0=E7=BB=84=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化代码 --- docs/data-structure/array/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index be8a348c8..2cc351c20 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -260,6 +260,20 @@ class Solution: return i + 1 ``` +优化 + +```python +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + i = 0 + for j in range(1, len(nums)): + # 两者不想等时 + if nums[i] != nums[j]: + i += 1 + nums[i] = nums[j] + return i + 1 +``` + ## 27. 移除元素 [原题链接](https://leetcode-cn.com/problems/remove-element/description/) From ee270897f4d5be58623ab457e52163a21dc84a31 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 17 Aug 2020 11:35:02 +0800 Subject: [PATCH 155/181] =?UTF-8?q?=F0=9F=90=B1(array):=2080.=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8E=92=E5=BA=8F=E6=95=B0=E7=BB=84=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E9=A1=B9=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补充解法 --- docs/data-structure/array/README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 2cc351c20..8f7fc3ed6 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1015,6 +1015,7 @@ class Solution(object): - 此时要删除 `nums[i + 2]` 就要向后找到一个 `nums[j]`(满足 `nums[j] != nums[i]`)替换 `nums[i + 2]` ```python +# 这个好理解一些 class Solution(object): def removeDuplicates(self, nums): """ @@ -1032,7 +1033,27 @@ class Solution(object): nums[i + 2] = nums[j] i = i + 1 - return i+2 + return i + 2 +``` + +补充解法: + +```python +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + i, count = 1, 1 + for j in range(1, len(nums)): + if nums[j] == nums[j - 1]: + count += 1 + else: + count = 1 + + if count <= 2: + # 相同的数 <= 2,跳过 i + nums[i] = nums[j] + i += 1 + + return i ``` From 8aa6a46b794edfd42dac2b521633b60ff7363d77 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 17 Aug 2020 11:37:17 +0800 Subject: [PATCH 156/181] =?UTF-8?q?=F0=9F=90=B1(array):=2080.=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8E=92=E5=BA=8F=E6=95=B0=E7=BB=84=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E9=A1=B9=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 精简解法 --- docs/data-structure/array/README.md | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 8f7fc3ed6..a9e2658f6 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1016,23 +1016,14 @@ class Solution(object): ```python # 这个好理解一些 -class Solution(object): - def removeDuplicates(self, nums): - """ - :type nums: List[int] - :rtype: int - """ - length = len(nums) - - if length <= 2: - return length - +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: i = 0 - for j in range(2, length): + for j in range(2, len(nums)): if nums[i] != nums[j]: nums[i + 2] = nums[j] - i = i + 1 - + i += 1 + # i 指向最后一个被交换的元素 return i + 2 ``` From 9cde1f190fcfa14b93cffc1e382ed8969a5e98cd Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 28 Aug 2020 11:13:40 +0800 Subject: [PATCH 157/181] =?UTF-8?q?=F0=9F=90=B1(string):=20125.=20?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=9B=9E=E6=96=87=E4=B8=B2=20=E5=A4=8D?= =?UTF-8?q?=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 4 +--- docs/data-structure/string/README.md | 32 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index a9e2658f6..be584267f 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -1323,9 +1323,7 @@ func maxProfit(prices []int) int { [原题链接](https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/comments/) -### 思路 - -双指针 +### 解一:双指针 - 指针 i 指向最左端,从左到右依次循环 - 指针 j 指向最右端,从右到左依次循环 diff --git a/docs/data-structure/string/README.md b/docs/data-structure/string/README.md index ef82c62bf..ec24d72e3 100644 --- a/docs/data-structure/string/README.md +++ b/docs/data-structure/string/README.md @@ -924,6 +924,38 @@ class Solution(object): return True ``` +复盘: + +```python +class Solution: + def isPalindrome(self, s: str) -> bool: + length = len(s) + i = 0 + j = length - 1 + + while i < j: + if self.isValid(s[i]) and self.isValid(s[j]): + if s[i].lower() != s[j].lower(): + return False + i += 1 + j -= 1 + + if not self.isValid(s[i]): + i += 1 + + if not self.isValid(s[j]): + j -= 1 + return True + + def isValid(self, c): + if c.isdigit() or c.isalpha(): + return True + return False +``` + +- 时间复杂度:`O(n)` +- 空间复杂度:`O(1)` + ## 139. 单词拆分 From f56adb78c34f805383a4cb1a9f0c6d9ca6d77e0a Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 11 Sep 2020 10:19:33 +0800 Subject: [PATCH 158/181] =?UTF-8?q?=F0=9F=90=B1(backtrace):=20216.=20?= =?UTF-8?q?=E7=BB=84=E5=90=88=E6=80=BB=E5=92=8C=20III?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/backtrack/README.md | 52 ++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/algorithm/backtrack/README.md b/docs/algorithm/backtrack/README.md index ef98f9757..ad7d18505 100644 --- a/docs/algorithm/backtrack/README.md +++ b/docs/algorithm/backtrack/README.md @@ -83,4 +83,56 @@ class Solution: track = [] track_back(nums, track) return ans +``` + +## 216. 组合总和 III + +[原题链接](https://leetcode-cn.com/problems/combination-sum-iii/) + +回溯模板: + +``` +backtracking() { + if (终止条件) { + 存放结果; + } + + for (选择:选择列表(可以想成树中节点孩子的数量)) { + 递归,处理节点; + backtracking(); + 回溯,撤销处理结果 + } +} +``` + +### 题解 + +```python +class Solution: + def combinationSum3(self, k: int, n: int) -> List[List[int]]: + ans = [] + ''' + element: 数组内答案 + start: 遍历的开始位置 + num: 剩余数字 + ''' + def dfs(element, start, num): + # 符合条件,加入最终答案,结束递归 + if len(element) == k or num < 0: + if len(element) == k and num == 0: + # print(element) + # 深拷贝 + ans.append(element[:]) + return + + for i in range(start, 10): + # 加入当前值 + element.append(i) + # 递归 + dfs(element, i + 1, num - i) + # 撤销选择,即回溯 + element.pop() + + dfs([], 1, n) + return ans ``` \ No newline at end of file From 59359e365405e49731c4f3dbb74537e284dcc41b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 11 Sep 2020 10:45:54 +0800 Subject: [PATCH 159/181] =?UTF-8?q?=F0=9F=90=B1(backtrace):=20216.=20?= =?UTF-8?q?=E7=BB=84=E5=90=88=E6=80=BB=E5=92=8C=20III=20=E8=A1=A5=E5=85=85?= =?UTF-8?q?=20Golang?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/backtrack/README.md | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/backtrack/README.md b/docs/algorithm/backtrack/README.md index ad7d18505..e028b46dd 100644 --- a/docs/algorithm/backtrack/README.md +++ b/docs/algorithm/backtrack/README.md @@ -107,6 +107,10 @@ backtracking() { ### 题解 + + +#### **Python** + ```python class Solution: def combinationSum3(self, k: int, n: int) -> List[List[int]]: @@ -135,4 +139,33 @@ class Solution: dfs([], 1, n) return ans -``` \ No newline at end of file +``` + +#### **Go** + +```go +func combinationSum3(k int, n int) [][]int { + ans := [][]int{} + dfs(&ans, []int{}, 1, n, k) + return ans +} + +func dfs(ans *[][]int, element []int, start int, num int, k int) { + if len(element) == k || num <= 0 { + if len(element) == k && num == 0 { + temp := make([]int, k) + copy(temp, element) + *ans = append(*ans, temp) + } + return + } + + for i:=start; i < 10; i++ { + element = append(element, i) + dfs(ans, element, i + 1, num - i, k) + element = element[:len(element) - 1] + } +} +``` + + \ No newline at end of file From 8e51cf553f9a306a89add88babbfbb94a2eba3c7 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 16 Sep 2020 18:03:23 +0800 Subject: [PATCH 160/181] =?UTF-8?q?=F0=9F=90=B1(recursion):=20226.=20?= =?UTF-8?q?=E7=BF=BB=E8=BD=AC=E4=BA=8C=E5=8F=89=E6=A0=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/recursion/README.md | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/algorithm/recursion/README.md b/docs/algorithm/recursion/README.md index 6e0de86b9..e4ade5b35 100644 --- a/docs/algorithm/recursion/README.md +++ b/docs/algorithm/recursion/README.md @@ -1,3 +1,34 @@ +## 226. 翻转二叉树 + +[原题链接](https://leetcode-cn.com/problems/invert-binary-tree/) + +### 思路 + +递归。 + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def invertTree(self, root: TreeNode) -> TreeNode: + if root is None: + return root + + # 翻转左子树 + left = self.invertTree(root.left) + # 翻转右子树 + right = self.invertTree(root.right) + + root.left, root.right = right, left + + return root +``` + ## 341. 扁平化嵌套列表迭代器 [原题链接](https://leetcode-cn.com/problems/flatten-nested-list-iterator/) From 926cf295a3a18e77341e8eefd9109b4bd20ebdf1 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 18 Sep 2020 18:06:30 +0800 Subject: [PATCH 161/181] =?UTF-8?q?=F0=9F=90=B1(backtrack):=20357.=20?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E5=90=84=E4=B8=AA=E4=BD=8D=E6=95=B0=E4=B8=8D?= =?UTF-8?q?=E5=90=8C=E7=9A=84=E6=95=B0=E5=AD=97=E4=B8=AA=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/backtrack/README.md | 76 +++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/docs/algorithm/backtrack/README.md b/docs/algorithm/backtrack/README.md index e028b46dd..d4e00b278 100644 --- a/docs/algorithm/backtrack/README.md +++ b/docs/algorithm/backtrack/README.md @@ -168,4 +168,78 @@ func dfs(ans *[][]int, element []int, start int, num int, k int) { } ``` - \ No newline at end of file + + +## 357. 计算各个位数不同的数字个数 + +[原题链接](https://leetcode-cn.com/problems/count-numbers-with-unique-digits/) + +### 解法一:回溯 + +用 `tags` 数组标记 0~9 数字出现的次数,再调用递归后进行回溯。注意对 0 进行特殊处理。 + +```python +class Solution: + ans = 0 + tags = [] # 记录数字出现的次数 + def countNumbersWithUniqueDigits(self, n: int) -> int: + # 0-9 的数字 + self.tags = [0 for _ in range(10)] + # 枚举所有数字:回溯 + """ + r: 轮次 + num: 数字 + """ + def dfs(r, num = 0): + if r <= 0: + # 结束递归 + return + + for i in range(10): + # 循环 0-9 + if num % 10 != i and self.tags[i] == 0: + # 条件枝剪 + self.ans += 1 + # 数字出现标记 + self.tags[i] = 1 + dfs(r - 1, num * 10 + i) + # 回溯 + self.tags[i] = 0 + + dfs(n) + # 补充 0 + return self.ans + 1 +``` + +### 解法二:动态规划 + +排列组合。 + +- `f(0) = 1` +- `f(1) = 9` +- `f(2) = 9 * 9 + f(1)` + - 第一个数字选择 1~9 + - 第二个数在 0~9 中选择和第一个数不同的数 +- `f(3) = 9 * 9 * 8 + f(2)` + +可以推出动态规划方程: + +``` +dp[i] = sum + dp[i - 1] +``` + +```python +class Solution: + def countNumbersWithUniqueDigits(self, n: int) -> int: + dp = [0 for _ in range(n + 1)] + # n = 1 时 + dp[0] = 1 + + for i in range(1, n + 1): + s = 9 + for j in range(1, i): + s *= (10 - j) + dp[i] = s + dp[i - 1] + + return dp[n] +``` \ No newline at end of file From 5d780178754f744d3747ee309ec06120d1e121c0 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 23 Oct 2020 10:01:42 +0800 Subject: [PATCH 162/181] =?UTF-8?q?=F0=9F=90=B1(double-pointer):=20763.=20?= =?UTF-8?q?=E5=88=92=E5=88=86=E5=AD=97=E6=AF=8D=E5=8C=BA=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/double-pointer/README.md | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/algorithm/double-pointer/README.md b/docs/algorithm/double-pointer/README.md index 61e72c7fe..8df804fe2 100644 --- a/docs/algorithm/double-pointer/README.md +++ b/docs/algorithm/double-pointer/README.md @@ -219,6 +219,49 @@ class Solution { } ``` +## 763. 划分字母区间 + +[原题链接](https://leetcode-cn.com/problems/partition-labels/) + +### 思路 + +- 哈希 +- 双指针 + +```python +class Solution: + def partitionLabels(self, S: str) -> List[int]: + # 字母最后出现的位置 + letter_ends = dict() + for i in range(len(S)): + s = S[i] + letter_ends[s] = i + + ans = list() + start = 0 + + while start < len(S): + begin = start + # 字母最后出现的位置 + end = letter_ends[S[start]] + while start < end: + letter = S[start] + letter_end = letter_ends[letter] + # 如果字母最后出现位置大于 end,对 end 进行更新 + if letter_end > end: + end = letter_end + start += 1 + ans.append(end - begin + 1) + start = end + 1 + + return ans +``` + +### 复杂度 + +- 时间复杂度:`O(n)` +- 空间复杂度:`O(26)` + ## 面试题 10.01. 合并排序的数组 From 8a1da87b2aabdd1b1e874414cd83bd43667f1ca8 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 3 Dec 2020 22:44:16 +0800 Subject: [PATCH 163/181] =?UTF-8?q?=F0=9F=90=B1(stack):=2084.=20=E6=9F=B1?= =?UTF-8?q?=E7=8A=B6=E5=9B=BE=E4=B8=AD=E6=9C=80=E5=A4=A7=E7=9A=84=E7=9F=A9?= =?UTF-8?q?=E5=BD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/stack/README.md | 90 +++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/docs/data-structure/stack/README.md b/docs/data-structure/stack/README.md index bfac36b06..848ab68e8 100644 --- a/docs/data-structure/stack/README.md +++ b/docs/data-structure/stack/README.md @@ -47,6 +47,96 @@ class Solution(object): return True ``` +## 84. 柱状图中最大的矩形 + +[原题链接](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/) + +### 解法一 + +- 单调栈 +- 逐个遍历 +- 结果:超时 + +```python +class Solution: + def largestRectangleArea(self, heights: List[int]) -> int: + stack = [] # 单调递增栈 + ans = 0 + for h in heights: + stack.append(h) + # if len(stack) == 0: + # stack.append(h) + # else: + # while stack[-1] > h: + # # 对比栈顶元素 + # top = stack[-1] + # # 左侧更大的数字被化为小数 + # if top > h: + # stack[-1] = h + # stack.append(h) + # print(stack) + # 计算实际面积 + stack_length = len(stack) + for i in range(stack_length): + # element = stack[i] + if stack[i] > h: + stack[i] = h + area = (stack_length - i) * stack[i] + ans = max(ans, area) + # print(ans) + + return ans +``` + +### 解法二 + +面积计算方式: + +- 找到 `heights[i]` 左侧第一个小于它的元素位置 `left` +- 找到 `heights[i]` 右侧第一个小于它的元素位置 `right` +- `area = (right - left - 1) * heights[i]` + +利用维护单调递增栈得出元素的左右边界: + +- 左侧边界(左侧第一个小于当前位置的元素)可以在元素入栈时确认 +- 右侧边界(右侧第一个小于当前位置的元素)可以在元素出栈时确认 + +```python +class Solution: + def largestRectangleArea(self, heights: List[int]) -> int: + # 找左侧第一个小于 h 的位置 left + # 右侧第一个小于 h 的位置 right + # area = (right - left) * h + + # 维护单调栈 + length = len(heights) + stack = [] + lefts = [-1 for _ in range(length)] + rights = [length for _ in range(length)] + for i in range(length): + h = heights[i] + if len(stack) == 0: + stack.append((i, h)) + else: + # 维护单调栈 + while len(stack) > 0 and stack[-1][1] >= h: + # 弹出时能确认右侧最小元素 + min_element = stack.pop() + rights[min_element[0]] = i + # 入栈,确认左侧最小元素 + if len(stack) > 0: + lefts[i] = stack[-1][0] + stack.append((i, h)) + + ans = 0 + for i in range(length): + area = (rights[i] - lefts[i] - 1) * heights[i] + # print((rights[i] - lefts[i] + 1)) + ans = max(area, ans) + + return ans +``` + ## 150. 逆波兰表达式求值 [原题链接](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/) From cb915311c9c9572c21af20d5f8f24bb69db2e3ab Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 7 Dec 2020 20:40:00 +0800 Subject: [PATCH 164/181] =?UTF-8?q?=F0=9F=90=B1(greedy):=20860.=20?= =?UTF-8?q?=E6=9F=A0=E6=AA=AC=E6=B0=B4=E6=89=BE=E9=9B=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/greedy/README.md | 43 +++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docs/algorithm/greedy/README.md b/docs/algorithm/greedy/README.md index d530c91e3..17fd025ab 100644 --- a/docs/algorithm/greedy/README.md +++ b/docs/algorithm/greedy/README.md @@ -664,6 +664,49 @@ class Solution { - 时间复杂度:`O(n)` - 空间复杂度:`O(n)` +## 860. 柠檬水找零 + +[原题链接](https://leetcode-cn.com/problems/lemonade-change/) + +### 思路 + +按顺序模拟找零顺序即可。 + +```python +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + count_5 = 0 + count_10 = 0 + + for bill in bills: + if bill == 5: + count_5 += 1 + elif bill == 10: + if count_5 == 0: + return False + count_5 -= 1 + count_10 += 1 + else: + if count_10 == 0: + if count_5 < 3: + return False + else: + count_5 -= 3 + else: + if count_5 == 0: + return False + else: + count_10 -= 1 + count_5 -= 1 + + return True +``` + +### 复杂度 + +- 时间复杂度:O(n) +- 空间复杂度:O(1) + ## 955. 删列造序 II [原题链接](https://leetcode-cn.com/problems/delete-columns-to-make-sorted-ii/) From 638ac51fc5865292ba4b70bf5c2febb95a76e361 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 9 Dec 2020 21:20:57 +0800 Subject: [PATCH 165/181] =?UTF-8?q?=F0=9F=90=B3(string):=20242.=20?= =?UTF-8?q?=E6=9C=89=E6=95=88=E7=9A=84=E5=AD=97=E6=AF=8D=E5=BC=82=E4=BD=8D?= =?UTF-8?q?=E8=AF=8D=20=E8=A1=A5=E5=85=85=20sort=20=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/string/README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/data-structure/string/README.md b/docs/data-structure/string/README.md index ec24d72e3..5cfa658c7 100644 --- a/docs/data-structure/string/README.md +++ b/docs/data-structure/string/README.md @@ -1109,7 +1109,7 @@ class Solution(object): [原题链接](https://leetcode-cn.com/problems/valid-anagram/) -### 思路 +### 解法一:哈希 - 统计 s 和 t 中所有字母出现的次数 - 判断是否相同 @@ -1142,6 +1142,22 @@ class Solution(object): return True ``` +- 时间复杂度:O(n) +- 空间复杂度:O(n) + +### 解法二:排序 + +```python +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + s = sorted(s) + t = sorted(t) + return s == t +``` + +- 时间复杂度:O(nlogn) +- 空间复杂度:O(1) + ### 顺便复习 Python 字典 创建字典 From 37cc2275a0477f25da3cbfc718b18a362eacd8e9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 9 Dec 2020 21:36:51 +0800 Subject: [PATCH 166/181] =?UTF-8?q?=F0=9F=90=B3(array):=2049.=20=E5=AD=97?= =?UTF-8?q?=E6=AF=8D=E5=BC=82=E4=BD=8D=E8=AF=8D=E5=88=86=E7=BB=84=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=AD=97=E7=AC=A6=E4=B8=B2=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8C=96=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index be584267f..d11d065bc 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -816,6 +816,24 @@ class Solution(object): return ans.values() ``` +普通写法,序列化为字符串: + +```python +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + table = dict() + for string in strs: + sort_string = "".join(sorted(string)) + if sort_string not in table: + table[sort_string] = [] + table[sort_string].append(string) + ans = [x for x in table.values()] + return ans +``` + +- 时间复杂度:O(n*klogk)(`n` 是 `strs` 长度,`k` 是 `strs` 中字符串的最大长度) +- 空间复杂度:O(n*k),存储在 `ans` 中的所有信息内容 + ### 参考资料 - [Python中collections.defaultdict()使用](https://www.jianshu.com/p/26df28b3bfc8) From 819be300e556097c564278e0b0c1ab60195d83a6 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 12 Jan 2021 17:08:22 +0800 Subject: [PATCH 167/181] =?UTF-8?q?=F0=9F=90=B1(tree):=20107.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E5=B1=82=E5=BA=8F=E9=81=8D=E5=8E=86?= =?UTF-8?q?=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/bfs/README.md | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/docs/data-structure/tree/bfs/README.md b/docs/data-structure/tree/bfs/README.md index c42c4db32..146dd9600 100644 --- a/docs/data-structure/tree/bfs/README.md +++ b/docs/data-structure/tree/bfs/README.md @@ -80,6 +80,41 @@ func levelOrder(root *TreeNode) [][]int { } ``` +## 107. 二叉树的层序遍历 II + +[原题链接](https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/) + +与 106 类似,只是结果输出顺序不同。 + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def levelOrderBottom(self, root: TreeNode) -> List[List[int]]: + ans = [] + q = [root] + while len(q) != 0: + # 遍历一层 + tmp = [] + for i in range(len(q)): + top = q[0] + del q[0] + if top is None: + continue + tmp.append(top.val) + q.append(top.left) + q.append(top.right) + if len(tmp) != 0: + ans.append(tmp) + + return ans[::-1] +``` + ## 108. 将有序数组转换为二叉搜索树 From ba9c878bd0c627a4aa4d05bec4ff3e3c33501756 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 13 Jan 2021 16:43:54 +0800 Subject: [PATCH 168/181] =?UTF-8?q?=F0=9F=90=B3(dfs):=2098.=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E4=BA=8C=E5=8F=89=E6=90=9C=E7=B4=A2=E6=A0=91=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=20while=20=E4=B8=AD=E5=BA=8F=E9=81=8D?= =?UTF-8?q?=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/dfs/README.md | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/data-structure/tree/dfs/README.md b/docs/data-structure/tree/dfs/README.md index 0e031374e..f0df6ddc5 100644 --- a/docs/data-structure/tree/dfs/README.md +++ b/docs/data-structure/tree/dfs/README.md @@ -231,6 +231,35 @@ func helper(root *TreeNode, low int, high int) bool { } ``` +### 解三:栈辅助中序遍历 + +```python +# 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 isValidBST(self, root: TreeNode) -> bool: + stack = [] + pre = float('-inf') + while root is not None or len(stack) > 0: + # 左侧压入栈 + while root is not None: + stack.append(root) + root = root.left + # 弹出栈顶 + top = stack.pop() + # 判断终序遍历前 1 个数是否小于当前数 + if top.val <= pre: + return False + pre = top.val + root = top.right + + return True +``` + ## 105. 从前序与中序遍历序列构造二叉树 From ab41c10e416d6969ef1182605c8c3ce25886d926 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 13 Jan 2021 16:51:58 +0800 Subject: [PATCH 169/181] =?UTF-8?q?=F0=9F=90=B3(tree):=20104.=20=E4=BA=8C?= =?UTF-8?q?=E5=8F=89=E6=A0=91=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6?= =?UTF-8?q?=20=E5=A4=8D=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/tree/recursion/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/data-structure/tree/recursion/README.md b/docs/data-structure/tree/recursion/README.md index 4981dcf7e..bf7e753d8 100644 --- a/docs/data-structure/tree/recursion/README.md +++ b/docs/data-structure/tree/recursion/README.md @@ -126,6 +126,25 @@ class Solution(object): return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1 ``` +20210113 复盘: + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def maxDepth(self, root: TreeNode) -> int: + if root is None: + return 0 + left_depth = self.maxDepth(root.left) + 1 + right_depth = self.maxDepth(root.right) + 1 + return max(left_depth, right_depth) +``` + #### **Go** ```go From 42a8a36f3e3b964ff9ae13f17dea226605de14fb Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 13 Jan 2021 17:29:13 +0800 Subject: [PATCH 170/181] =?UTF-8?q?=F0=9F=90=B1(array):=20830.=20=E8=BE=83?= =?UTF-8?q?=E5=A4=A7=E5=88=86=E7=BB=84=E7=9A=84=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index d11d065bc..bab1b11c8 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2935,6 +2935,32 @@ func getMin(a int, b int) int { } ``` +## 830. 较大分组的位置 + +[原题链接](https://leetcode-cn.com/problems/positions-of-large-groups/) + +### 顺序遍历 + +判断前后两个连续字母是否相同,若字母连续且当前字母连续出现次数已 >=3,那么加入结果集中。 + +```python +class Solution: + def largeGroupPositions(self, s: str) -> List[List[int]]: + length = len(s) + ans = [] + count = 1 + for i in range(length): + if i == length - 1 or s[i] != s[i + 1]: + # 出现不连续字母 + if count >= 3: + ans.append([i - count + 1, i]) + count = 1 + else: + count += 1 + + return ans +``` + ## 914. 卡牌分组 [原题链接](https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/) From 6af2984b93526bae0b6f2274b0d8a9a1fbc43a11 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 25 Feb 2021 15:17:40 +0800 Subject: [PATCH 171/181] =?UTF-8?q?=F0=9F=90=B1(array):=20832.=20=E7=BF=BB?= =?UTF-8?q?=E8=BD=AC=E5=9B=BE=E5=83=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index bab1b11c8..9a0854bbf 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2961,6 +2961,31 @@ class Solution: return ans ``` +## 832. 翻转图像 + +[原题链接](https://leetcode-cn.com/problems/flipping-an-image/) + +### 思路 + +遍历二维数组,利用双指针进行元素的原地替换。 + +```python +class Solution: + def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]: + for line in A: + line_length = len(line) + for i in range(line_length): + j = line_length - 1 - i + if i < j: + line[i], line[j] = line[j], line[i] + line[i] = 1 - line[i] + line[j] = 1 - line[j] + elif i == j: + line[i] = 1 - line[i] + + return A +``` + ## 914. 卡牌分组 [原题链接](https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/) From ecc9320c5692f25afcbfb9382c44bcec0e7fa00b Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 26 Feb 2021 11:15:40 +0800 Subject: [PATCH 172/181] =?UTF-8?q?=F0=9F=90=B1(array):=20867.=20=E8=BD=AC?= =?UTF-8?q?=E7=BD=AE=E7=9F=A9=E9=98=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 9a0854bbf..40ccd4255 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2986,6 +2986,28 @@ class Solution: return A ``` +## 867. 转置矩阵 + +[原题链接](https://leetcode-cn.com/problems/transpose-matrix/) + +### 思路 + +模拟矩阵转置过程,即二维数组下标参数兑换:`ans[j][i] = matrix[i][j]`。 + +```python +class Solution: + def transpose(self, matrix: List[List[int]]) -> List[List[int]]: + m = len(matrix) + n = len(matrix[0]) + ans = [[0 for _ in range(m)] for _ in range(n)] + + for i in range(m): + for j in range(n): + ans[j][i] = matrix[i][j] + + return ans +``` + ## 914. 卡牌分组 [原题链接](https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/) From 3e4916b871d6cce54c2587daee4b892f17ad2103 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 26 Feb 2021 14:36:01 +0800 Subject: [PATCH 173/181] =?UTF-8?q?=F0=9F=90=B1(array):=20867.=20=E8=BD=AC?= =?UTF-8?q?=E7=BD=AE=E7=9F=A9=E9=98=B5=20=E8=A1=A5=E5=85=85=20Go=20?= =?UTF-8?q?=E8=AF=AD=E8=A8=80=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/array/README.md | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/data-structure/array/README.md b/docs/data-structure/array/README.md index 40ccd4255..829b141f9 100644 --- a/docs/data-structure/array/README.md +++ b/docs/data-structure/array/README.md @@ -2994,6 +2994,10 @@ class Solution: 模拟矩阵转置过程,即二维数组下标参数兑换:`ans[j][i] = matrix[i][j]`。 + + +#### **Python** + ```python class Solution: def transpose(self, matrix: List[List[int]]) -> List[List[int]]: @@ -3008,6 +3012,34 @@ class Solution: return ans ``` +#### **Go** + +```go +func transpose(matrix [][]int) [][]int { + m := len(matrix) + n := len(matrix[0]) + ans := make([][]int, n) + // 初始化 + for i := range ans { + ans[i] = make([]int, m) + for j := range ans[i] { + ans[i][j] = 0 + } + } + + // 赋值 + for i, row:= range matrix { + for j, v := range row { + ans[j][i] = v + } + } + + return ans +} +``` + + + ## 914. 卡牌分组 [原题链接](https://leetcode-cn.com/problems/x-of-a-kind-in-a-deck-of-cards/) From e7a3d3d331d0a8fe1e6bebccebba2919d179ffaf Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 1 Mar 2021 14:38:12 +0800 Subject: [PATCH 174/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20303.=20?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=E5=92=8C=E6=A3=80=E7=B4=A2=20-=20=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E4=B8=8D=E5=8F=AF=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index bc4e3a1e3..c20f2f36e 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1057,6 +1057,39 @@ class Solution: return len(tails) ``` +## 303. 区域和检索 - 数组不可变 + +[原题链接](https://leetcode-cn.com/problems/range-sum-query-immutable/) + +### 思路 + +动态规划前缀和。 + +```python +class NumArray: + + def __init__(self, nums: List[int]): + length = len(nums) + self.sum_nums = [0 for _ in range(length)] + for i in range(length): + if i == 0: + self.sum_nums[i] = nums[i] + else: + self.sum_nums[i] = self.sum_nums[i - 1] + nums[i] + + + def sumRange(self, i: int, j: int) -> int: + if i == 0: + return self.sum_nums[j] + else: + return self.sum_nums[j] - self.sum_nums[i - 1] + + +# Your NumArray object will be instantiated and called as such: +# obj = NumArray(nums) +# param_1 = obj.sumRange(i,j) +``` + ## 309. 最佳买卖股票时机含冷冻期 [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) From 7f633e4df26aab3d8f5e8ad4c8b95fa11d76b1a2 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Mon, 1 Mar 2021 17:16:07 +0800 Subject: [PATCH 175/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20303.=20?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=E5=92=8C=E6=A3=80=E7=B4=A2=20-=20=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E4=B8=8D=E5=8F=AF=E5=8F=98=20=E8=A1=A5=E5=85=85=20Gol?= =?UTF-8?q?ang=20=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index c20f2f36e..c827e47e0 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1065,6 +1065,10 @@ class Solution: 动态规划前缀和。 + + +#### **Python** + ```python class NumArray: @@ -1090,6 +1094,46 @@ class NumArray: # param_1 = obj.sumRange(i,j) ``` +#### **Go** + +```go +type NumArray struct { + sums []int +} + + +func Constructor(nums []int) NumArray { + length := len(nums) + sums := make([]int, length) + for i, num := range nums { + if i == 0 { + sums[i] = num + } else { + sums[i] = sums[i - 1] + num + } + } + return NumArray{sums} +} + + +func (this *NumArray) SumRange(i int, j int) int { + if i == 0 { + return this.sums[j] + } else { + return this.sums[j] - this.sums[i - 1] + } +} + + +/** + * Your NumArray object will be instantiated and called as such: + * obj := Constructor(nums); + * param_1 := obj.SumRange(i,j); + */ +``` + + + ## 309. 最佳买卖股票时机含冷冻期 [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) From e5a6b93a9068faf58c31682298da9bfb0602efd9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 2 Mar 2021 11:17:18 +0800 Subject: [PATCH 176/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20304.=20?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E5=8C=BA=E5=9F=9F=E5=92=8C=E6=A3=80=E7=B4=A2?= =?UTF-8?q?=20-=20=E7=9F=A9=E9=98=B5=E4=B8=8D=E5=8F=AF=E5=8F=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index c827e47e0..cc8fa80cd 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1134,6 +1134,34 @@ func (this *NumArray) SumRange(i int, j int) int { +## 304. 二维区域和检索 - 矩阵不可变 + +[原题链接](https://leetcode-cn.com/problems/range-sum-query-2d-immutable/) + +### 解法一:二维前缀和 + +```python +class NumMatrix: + + def __init__(self, matrix: List[List[int]]): + m = len(matrix) + n = len(matrix[0]) if matrix else 0 + self.sums = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + + for i in range(m): + for j in range(n): + self.sums[i + 1][j + 1] = self.sums[i][j + 1] + self.sums[i + 1][j] - self.sums[i][j] + matrix[i][j] + + + def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int: + return self.sums[row2 + 1][col2 + 1] - self.sums[row2 + 1][col1] - self.sums[row1][col2 + 1] + self.sums[row1][col1] + + +# Your NumMatrix object will be instantiated and called as such: +# obj = NumMatrix(matrix) +# param_1 = obj.sumRegion(row1,col1,row2,col2) +``` + ## 309. 最佳买卖股票时机含冷冻期 [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) From 1614d487edf5c144228dcd882222aa21b7c99683 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 2 Mar 2021 14:32:45 +0800 Subject: [PATCH 177/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20304.=20?= =?UTF-8?q?=E4=BA=8C=E7=BB=B4=E5=8C=BA=E5=9F=9F=E5=92=8C=E6=A3=80=E7=B4=A2?= =?UTF-8?q?=20-=20=E7=9F=A9=E9=98=B5=E4=B8=8D=E5=8F=AF=E5=8F=98=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Golang=20=E8=A7=A3=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 46 ++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index cc8fa80cd..89b5385f4 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1140,6 +1140,10 @@ func (this *NumArray) SumRange(i int, j int) int { ### 解法一:二维前缀和 + + +#### **Python** + ```python class NumMatrix: @@ -1162,6 +1166,48 @@ class NumMatrix: # param_1 = obj.sumRegion(row1,col1,row2,col2) ``` +#### **Go** + +```go +type NumMatrix struct { + sums [][]int +} + + +func Constructor(matrix [][]int) NumMatrix { + m := len(matrix) + if m == 0 { + return NumMatrix{} + } + n := len(matrix[0]) + sums := make([][]int, m + 1) + // 初始化第 0 行 + sums[0] = make([]int, n + 1) + for i, row := range matrix { + sums[i + 1] = make([]int, n + 1) + for j, num := range row { + sums[i + 1][j + 1] = sums[i][j + 1] + sums[i + 1][j] - sums[i][j] + num + } + } + + return NumMatrix{sums} +} + + +func (this *NumMatrix) SumRegion(row1 int, col1 int, row2 int, col2 int) int { + return this.sums[row2 + 1][col2 + 1] - this.sums[row2 + 1][col1] - this.sums[row1][col2 + 1] + this.sums[row1][col1] +} + + +/** + * Your NumMatrix object will be instantiated and called as such: + * obj := Constructor(matrix); + * param_1 := obj.SumRegion(row1,col1,row2,col2); + */ +``` + + + ## 309. 最佳买卖股票时机含冷冻期 [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/) From e72a75dc8242e6005e83a39c1dbefa0351b8b3d1 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Wed, 3 Mar 2021 17:50:10 +0800 Subject: [PATCH 178/181] =?UTF-8?q?=F0=9F=90=B1(dynamic):=20338.=20?= =?UTF-8?q?=E6=AF=94=E7=89=B9=E4=BD=8D=E8=AE=A1=E6=95=B0=20=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E8=A7=A3=E6=B3=95=E4=BA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/algorithm/dynamic/README.md | 46 ++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/docs/algorithm/dynamic/README.md b/docs/algorithm/dynamic/README.md index 89b5385f4..d660b8b17 100644 --- a/docs/algorithm/dynamic/README.md +++ b/docs/algorithm/dynamic/README.md @@ -1316,12 +1316,11 @@ class Solution(object): return res[amount] ``` - ## 338. 比特位计数 [原题链接](https://leetcode-cn.com/problems/counting-bits/description/) -### 思路 +### 解法一 动态规划无疑了 @@ -1349,6 +1348,49 @@ class Solution(object): return List1[:num+1] ``` +### 解法二 + +奇偶数的二进制规律: + +- 奇数二进制数总比前一个偶数二进制数多 1 个 1(即最后 1 位) +- 偶数二进制数 `x` 中 1 的个数总等于 `x / 2` 中 1 的个数(除 2 等于右移 1 位,即抹去最后一位 0) + + + +c + +```python +class Solution: + def countBits(self, num: int) -> List[int]: + ans = [0 for _ in range(num + 1)] + for i in range(num + 1): + if i % 2 == 0: + # 偶数 + ans[i] = ans[i // 2] + else: + # 奇数 + ans[i] = ans[i - 1] + 1 + return ans +``` + +#### **Go** + +```go +func countBits(num int) []int { + ans := make([]int, num + 1) + for i := 0; i <= num; i++ { + if i % 2 == 0 { + ans[i] = ans[i / 2] + } else { + ans[i] = ans[i - 1] + 1 + } + } + return ans +} +``` + + + ## 714. 买卖股票的最佳时机含手续费 [原题链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/) From c413cb95b7ee93a66438577733266657a8b1db96 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Thu, 8 Apr 2021 13:18:50 +0800 Subject: [PATCH 179/181] =?UTF-8?q?=F0=9F=90=B1(research):=2081.=20?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E6=97=8B=E8=BD=AC=E6=8E=92=E5=BA=8F=E6=95=B0?= =?UTF-8?q?=E7=BB=84=20II?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index 7e244be43..df19b750e 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -488,6 +488,53 @@ func searchMatrix(matrix [][]int, target int) bool { } ``` +## 81. 搜索旋转排序数组 II + +[原题链接](https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/) + +### 思路 + +划分出有序数组进行二分查找。 + +当出现重复元素时,即 `nums[left] == nums[mid] && nums[right] == nums[mid]`,无法判断数组哪侧有序,应从两端往中间缩短查找范围。 + +```go +func search(nums []int, target int) bool { + length := len(nums) + left := 0 + right := length - 1 + + for left <= right { + mid := (left + right) / 2 + if nums[mid] == target { + return true + } + if nums[left] == nums[mid] && nums[right] == nums[mid] { + left++ + right-- + } else if nums[left] <= nums[mid] { + // 左侧更小 + // 左侧区间是否连续 + if target >= nums[left] && target < nums[mid] { + right = mid - 1 + } else { + left = mid + 1 + } + } else { + // 左侧更大 + // 右侧区间是否连续 + if target > nums[mid] && target <= nums[length - 1] { + left = mid + 1 + } else { + right = mid - 1 + } + } + } + + return false +} +``` + ## 153. 寻找旋转排序数组中的最小值 [原题链接](https://leetcode-cn.com/problems/find-minimum-in-rotated-sorted-array/) From 01be7556e37867cdf9afab97d3c87de6d9c509d9 Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Tue, 11 May 2021 12:58:42 +0800 Subject: [PATCH 180/181] =?UTF-8?q?=F0=9F=90=B1(binary-search):=201283.=20?= =?UTF-8?q?=E4=BD=BF=E7=BB=93=E6=9E=9C=E4=B8=8D=E8=B6=85=E8=BF=87=E9=98=88?= =?UTF-8?q?=E5=80=BC=E7=9A=84=E6=9C=80=E5=B0=8F=E9=99=A4=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../research/binary-search/README.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/docs/algorithm/research/binary-search/README.md b/docs/algorithm/research/binary-search/README.md index df19b750e..fc6580dc4 100644 --- a/docs/algorithm/research/binary-search/README.md +++ b/docs/algorithm/research/binary-search/README.md @@ -1240,4 +1240,58 @@ class Solution: right = mid - 1 return -1 +``` + +## 1283. 使结果不超过阈值的最小除数 + +[原题链接](https://leetcode-cn.com/problems/find-the-smallest-divisor-given-a-threshold/) + +### 读题 + +简单得说,就是找到一个正整数 `x`,把 `nums` 中的数依次除以该数,相加之和 `total` 需要小于阈值 `threshold`,且要求 `x` 最小。可知当 `total` 越接近 `threshold` 时,`x` 越小。 + +### 思路 + +因为数据量的原因(1 <= nums.length <= 5 * 10^4),我们不能通过暴力破解枚举所有可能的 `x`,可以想到应当使用二分查找,那么二分查找的区间如何定义呢? + +左侧值 `left` 选取最小正整数 1,而右侧值 `right` 可以选择数组 `nums` 中的最大数 `max(nums)`。当 `x` 取值为 `max(nums)` 时,结果和 `total` 等于数组长度,若此时 `x` 再继续增加,`total` 则始终保持不变。因此右侧区间取值 `max(nums)`,再取更大的值则没有意义。 + +### 实现 + +```go +func smallestDivisor(nums []int, threshold int) int { + // 寻找最大数 + maxNum := 1 + for _, num := range nums { + if num > maxNum { + maxNum = num + } + } + + left := 1 + right := maxNum + ans := 0 + for left <= right { + mid := (left + right) / 2 + // 计算总数 + total := 0 + for _, num := range nums { + total += num / mid + if num % mid > 0 { + total += 1 + } + } + + if total <= threshold { + // 找到满足条件的 mid 了,但还希望能找到更小的:往左边找 + right = mid - 1 + ans = mid + } else { + // total 太大了,应该要提高 mid:往右边找 + left = mid + 1 + } + } + + return ans +} ``` \ No newline at end of file From 8b55ef9d0ae6f7e025d27bdb9bf5d45f9c68e1cd Mon Sep 17 00:00:00 2001 From: JalanJiang <448300947@qq.com> Date: Fri, 21 May 2021 16:28:16 +0800 Subject: [PATCH 181/181] =?UTF-8?q?=F0=9F=90=B1(hash):=20609.=20=E5=9C=A8?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E4=B8=AD=E6=9F=A5=E6=89=BE=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/data-structure/hash/README.md | 47 ++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/data-structure/hash/README.md b/docs/data-structure/hash/README.md index e064be209..d5663217e 100644 --- a/docs/data-structure/hash/README.md +++ b/docs/data-structure/hash/README.md @@ -757,6 +757,53 @@ class Solution: return ans ``` +## 609. 在系统中查找重复文件 + +[原题链接](https://leetcode-cn.com/problems/find-duplicate-file-in-system/) + +### 思路 + +使用哈希表实现。将文件内容作为哈希 key 值,文件路径数组作为 value。 + +使用 Go 语言的哈希 + 数组表示:`contentMap := make(map[string][]string)`。 + +### 实现 + +```go +import "strings" + +func findDuplicate(paths []string) [][]string { + contentMap := make(map[string][]string) + ans := make([][]string, 0) + for _, pathString := range paths { + // 路径分割 + paths := strings.Split(pathString, " ") + document := "" + for idx, path := range paths { + if idx == 0 { + document = path + } else { + // 按括号切分 + contents := strings.Split(path, "(") + filePath := contents[0] + content := contents[1][:len(contents[1]) - 1] + + fullPath := document + "/" + filePath + contentMap[content] = append(contentMap[content], fullPath) + } + } + } + + for _, contents := range contentMap { + if len(contents) >= 2 { + ans = append(ans, contents) + } + } + + return ans +} +``` + ## 652. 寻找重复的子树 [原题链接](https://leetcode-cn.com/problems/find-duplicate-subtrees/)