From 3d87b36ad7681d4c3dae40529b41506c7a383554 Mon Sep 17 00:00:00 2001 From: Haitao Lu Date: Thu, 29 Dec 2022 00:20:09 +0800 Subject: [PATCH 01/21] =?UTF-8?q?=E5=9C=A8=E5=9B=BE=E7=89=87=E5=92=8C?= =?UTF-8?q?=E6=96=87=E5=AD=97=E6=AE=B5=E8=90=BD=E4=B8=AD=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E7=A9=BA=E8=A1=8C,=20=E4=BD=BF=E6=96=87?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E8=90=BD=E5=8F=AF=E4=BB=A5=E6=96=B0=E8=B5=B7?= =?UTF-8?q?=E4=B8=80=E8=A1=8C.=20=E5=A6=82=E6=9E=9C=E4=B8=8D=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=A9=BA=E8=A1=8C,=20=E6=96=87=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E8=90=BD=E4=BC=9A=E8=B7=9F=E5=9C=A8=E5=9B=BE=E7=89=87=E5=90=8E?= =?UTF-8?q?=E9=9D=A2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0028.实现strStr.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index fc222441..4e01926f 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -174,9 +174,11 @@ next数组就是一个前缀表(prefix table)。 长度为前1个字符的子串`a`,最长相同前后缀的长度为0。(注意字符串的**前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串**;**后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串**。) KMP精讲6 + 长度为前2个字符的子串`aa`,最长相同前后缀的长度为1。 KMP精讲7 + 长度为前3个字符的子串`aab`,最长相同前后缀的长度为0。 以此类推: From e7f3ecc58a575334ef02cada1407daa6c0d6d590 Mon Sep 17 00:00:00 2001 From: picassoboss <111678738+picassoboss@users.noreply.github.com> Date: Fri, 30 Dec 2022 14:12:01 +0800 Subject: [PATCH 02/21] =?UTF-8?q?Update=200494.=E7=9B=AE=E6=A0=87=E5=92=8C?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit java代码部分无法通过leetcode提交,需要先判断sum是否可以满足target --- problems/0494.目标和.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 6c8c28ec..eec4183d 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -270,6 +270,8 @@ class Solution { public int findTargetSumWays(int[] nums, int target) { int sum = 0; for (int i = 0; i < nums.length; i++) sum += nums[i]; + //如果target过大 sum将无法满足 + if ( target < 0 && sum < -target) return 0; if ((target + sum) % 2 != 0) return 0; int size = (target + sum) / 2; if(size < 0) size = -size; From 15e3377491590fceee2af002803183bd6f15e236 Mon Sep 17 00:00:00 2001 From: re1own <595875338@qq.com> Date: Fri, 30 Dec 2022 01:42:47 -0500 Subject: [PATCH 03/21] =?UTF-8?q?Update=200518.=E9=9B=B6=E9=92=B1=E5=85=91?= =?UTF-8?q?=E6=8D=A2II.md=20=E5=AF=B9dp[0]=3D1=E7=9A=84=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E8=A7=A3=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes problems/.DS_Store | Bin 0 -> 6148 bytes problems/0518.零钱兑换II.md | 3 +++ 3 files changed, 3 insertions(+) create mode 100644 .DS_Store create mode 100644 problems/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..da03c1c1b207c3ee04079084ecb15dcfff97ef95 GIT binary patch literal 6148 zcmeHK%}T>S5T317Q;OJwLXQhx3-<3)^bl)(0V4`psf{T$m}X1UTBHSVD*@yHz(SRn%3w1`N_?k*PTX z=s*u5cO3N-(d77z49It9K_3Pnz=e13&kcl&V-IdW@S|a|_{35R>BXgGloVwt;#QN%@Vis8VsHj`Xe9O(bW6^; z=;?2>^71?{rY9N=vv=!y_4uZF|F|A+0!!OY6cR47cXj`MRB4$Rg_Eiph0d}LrjcXRUo z-}}7&|CmHQVt^R zVC$RRxm?z$r5rK?vu`uAlgGYm1 zMLXL^w*hCgdN+$V`92QzXMC=vDCb;Xa{*8E#yp+f@nHS>C1gr@Cz5G$oj%rFb#~6y z&W3!?%%`Rbr~<0MqAP%&&6X^C)KL{s1yq4r0scN%IAbPQd32u+4DJX3j1hK*IiDrC z#tLSFl}BV?#+L$psgWaw@#TnHS(gb`9(_3($Bg?3vyl^uaqNg&x13DoQAbrk6$lmR z_{%Q$|IMGz|6!3{sRF9Nzf!=&c|Y%AOVV3go8w+<;R84uud6)PC78HYjJ4c~*Wk_& Yw>$x6f|W-^VEQBAWY9qs_)`Tw0S;+s82|tP literal 0 HcmV?d00001 diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md index 2fc807cd..f6a8044c 100644 --- a/problems/0518.零钱兑换II.md +++ b/problems/0518.零钱兑换II.md @@ -95,6 +95,8 @@ dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。 下标非0的dp[j]初始化为0,这样累计加dp[j - coins[i]]的时候才不会影响真正的dp[j] +dp[0]=1还说明了一种情况:如果正好选了coins[i]后,也就是j-coins[i] == 0的情况表示这个硬币刚好能选,此时dp[0]为1表示只选coins[i]存在这样的一种选法。 + 4. 确定遍历顺序 本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),还是外层for遍历背包(金钱总额),内层for循环遍历物品(钱币)呢? @@ -316,3 +318,4 @@ object Solution { + From 2cd16202f48ae765049c00a1a773214033b0e127 Mon Sep 17 00:00:00 2001 From: El nino <69737612+el-nino2020@users.noreply.github.com> Date: Mon, 2 Jan 2023 16:39:24 +0800 Subject: [PATCH 04/21] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b0e8d65..a04f58a6 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ 1. [数组过于简单,但你该了解这些!](./problems/数组理论基础.md) 2. [数组:二分查找](./problems/0704.二分查找.md) 3. [数组:移除元素](./problems/0027.移除元素.md) -4. [数组:序数组的平方](./problems/0977.有序数组的平方.md) +4. [数组:有序数组的平方](./problems/0977.有序数组的平方.md) 5. [数组:长度最小的子数组](./problems/0209.长度最小的子数组.md) 6. [数组:螺旋矩阵II](./problems/0059.螺旋矩阵II.md) 7. [数组:总结篇](./problems/数组总结篇.md) From fe0d0f8c5be965b69f2db0c966c2a8b7135e9f35 Mon Sep 17 00:00:00 2001 From: hbingzhi Date: Tue, 3 Jan 2023 17:46:01 +0800 Subject: [PATCH 05/21] =?UTF-8?q?232.=E4=BF=AE=E6=94=B9=E6=96=87=E5=AD=97?= =?UTF-8?q?=E5=8F=99=E8=BF=B0=E9=94=99=E8=AF=AF=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0232.用栈实现队列.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 4983c93a..efeb1046 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -38,7 +38,7 @@ queue.empty(); // 返回 false ## 思路 -《代码随想录》算法公开课:[栈的基本操作! | LeetCode:232.用栈实现队列](https://www.bilibili.com/video/BV1nY4y1w7VC),相信结合视频再看本篇题解,更有助于大家对链表的理解。 +《代码随想录》算法公开课:[栈的基本操作! | LeetCode:232.用栈实现队列](https://www.bilibili.com/video/BV1nY4y1w7VC),相信结合视频再看本篇题解,更有助于大家对栈和队列的理解。 这是一道模拟题,不涉及到具体算法,考察的就是对栈和队列的掌握程度。 @@ -662,3 +662,4 @@ impl MyQueue { + From 49fc701e4897acd528e60ac9a67d0d85772dbb5b Mon Sep 17 00:00:00 2001 From: huhaonan <812559558@qq.com> Date: Thu, 5 Jan 2023 21:42:53 +0800 Subject: [PATCH 06/21] =?UTF-8?q?UPDATE=200222=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=85=B6=E4=B8=AD=E4=B8=A4=E4=B8=AA=E9=94=99=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0222.完全二叉树的节点个数.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index b87877c9..10ac8264 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -188,7 +188,7 @@ public: ```CPP if (root == nullptr) return 0; -// 开始根据做深度和有深度是否相同来判断该子树是不是满二叉树 +// 开始根据左深度和右深度是否相同来判断该子树是不是满二叉树 TreeNode* left = root->left; TreeNode* right = root->right; int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便 @@ -843,3 +843,4 @@ impl Solution { + From 0c77206ecae5acece7cc12572ed08682b3147c20 Mon Sep 17 00:00:00 2001 From: Zeeland Date: Thu, 5 Jan 2023 22:01:19 +0800 Subject: [PATCH 07/21] =?UTF-8?q?update:=20=200104.=E4=BA=8C=E5=8F=89?= =?UTF-8?q?=E6=A0=91=E7=9A=84=E6=9C=80=E5=A4=A7=E6=B7=B1=E5=BA=A6:=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96python=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0102.二叉树的层序遍历.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 406242a7..3b68592f 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -2532,20 +2532,18 @@ class Solution: return 0 queue_ = [root] - result = [] + depth = 0 while queue_: length = len(queue_) - sub = [] for i in range(length): cur = queue_.pop(0) sub.append(cur.val) #子节点入队列 if cur.left: queue_.append(cur.left) if cur.right: queue_.append(cur.right) - result.append(sub) + depth += 1 - - return len(result) + return depth ``` Go: From abedcbbe040fff779f54ed7a68204e677bcaa24e Mon Sep 17 00:00:00 2001 From: Frank Mao Date: Fri, 6 Jan 2023 00:35:56 +0800 Subject: [PATCH 08/21] =?UTF-8?q?0150.=E9=80=86=E6=B3=A2=E5=85=B0=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E6=B1=82=E5=80=BC=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=9B=B4=E5=BF=AB=E9=80=9F=E7=9A=84python=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0150.逆波兰表达式求值.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 176ea687..f0323bc4 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -163,6 +163,25 @@ class Solution { python3 +```python +from operator import add, sub, mul + +class Solution: + op_map = {'+': add, '-': sub, '*': mul, '/': lambda x, y: int(x / y)} + + def evalRPN(self, tokens: List[str]) -> int: + stack = [] + for token in tokens: + if token not in {'+', '-', '*', '/'}: + stack.append(int(token)) + else: + op2 = stack.pop() + op1 = stack.pop() + stack.append(self.op_map[token](op1, op2)) # 第一个出来的在运算符后面 + return stack.pop() +``` + +另一种可行,但因为使用eval相对较慢的方法: ```python class Solution: def evalRPN(self, tokens: List[str]) -> int: From 256ca509ab75b5108a3c315ef6449431b0921def Mon Sep 17 00:00:00 2001 From: Zeeland Date: Fri, 6 Jan 2023 17:23:51 +0800 Subject: [PATCH 09/21] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96Python?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E9=AB=98=E4=BA=AE=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0042.接雨水.md | 4 ++-- problems/0257.二叉树的所有路径.md | 4 ++-- problems/前序/ACM模式如何构建二叉树.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/problems/0042.接雨水.md b/problems/0042.接雨水.md index e8dd3690..ac6f20f9 100644 --- a/problems/0042.接雨水.md +++ b/problems/0042.接雨水.md @@ -471,7 +471,7 @@ class Solution { ### Python: 双指针法 -```python3 +```Python class Solution: def trap(self, height: List[int]) -> int: res = 0 @@ -510,7 +510,7 @@ class Solution: return result ``` 单调栈 -```python3 +```Python class Solution: def trap(self, height: List[int]) -> int: # 单调栈 diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index 2d796671..d0c190a0 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -468,7 +468,7 @@ class Solution { --- ## Python: 递归法+隐形回溯 -```Python3 +```Python # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): @@ -499,7 +499,7 @@ class Solution: 迭代法: -```python3 +```Python from collections import deque diff --git a/problems/前序/ACM模式如何构建二叉树.md b/problems/前序/ACM模式如何构建二叉树.md index 01d5b255..42bf7af0 100644 --- a/problems/前序/ACM模式如何构建二叉树.md +++ b/problems/前序/ACM模式如何构建二叉树.md @@ -280,7 +280,7 @@ public class Solution { ## Python -```Python3 +```Python class TreeNode: def __init__(self, val = 0, left = None, right = None): self.val = val From 9b07639364f2586815b10fcec5cf209b169241a8 Mon Sep 17 00:00:00 2001 From: Logen <47022821+Logenleedev@users.noreply.github.com> Date: Sat, 7 Jan 2023 14:08:19 -0600 Subject: [PATCH 10/21] fix minor code style --- problems/0151.翻转字符串里的单词.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index a12d8f76..dc12ae23 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -442,7 +442,7 @@ class Solution: while left <= right and s[left] == ' ': #去除开头的空格 left += 1 while left <= right and s[right] == ' ': #去除结尾的空格 - right = right-1 + right -= 1 tmp = [] while left <= right: #去除单词中间多余的空格 if s[left] != ' ': From 2d2babdaf0ce7ceb3f61c26c7e959ed2776bda62 Mon Sep 17 00:00:00 2001 From: hbingzhi Date: Sun, 8 Jan 2023 12:58:54 +0800 Subject: [PATCH 11/21] =?UTF-8?q?349.=E6=9C=80=E5=90=8E=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E6=B7=BB=E5=8A=A0=E5=8F=A6=E4=B8=80=E7=A7=8D?= =?UTF-8?q?=E5=86=99=E6=B3=95=EF=BC=8C=E6=9B=B4=E5=A4=9A=E4=BA=BA=E5=AE=B9?= =?UTF-8?q?=E6=98=93=E7=90=86=E8=A7=A3=E7=9C=8B=E6=87=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0349.两个数组的交集.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 2e98ef6f..6f5a34e7 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -137,8 +137,18 @@ class Solution { resSet.add(i); } } - //将结果几何转为数组 + + //方法1:直接将结果几何转为数组 return resSet.stream().mapToInt(x -> x).toArray(); + + //方法2:另外申请一个数组存放setRes中的元素,最后返回数组 + int[] arr = new int[setRes.size()]; + int j = 0; + for(int i : setRes){ + arr[j++] = i; + } + + return arr; } } ``` @@ -423,3 +433,4 @@ C#: + From a008a740694b4fd99a307dab9e05a1f9276605f2 Mon Sep 17 00:00:00 2001 From: Logen <47022821+Logenleedev@users.noreply.github.com> Date: Sun, 8 Jan 2023 08:21:42 -0600 Subject: [PATCH 12/21] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/前序/vim.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/前序/vim.md b/problems/前序/vim.md index f84e70ac..5c5910d2 100644 --- a/problems/前序/vim.md +++ b/problems/前序/vim.md @@ -66,7 +66,7 @@ IDE那么很吃内存,打开个IDE卡半天,用VIM就很轻便了,秒开 ## 安装 -PowerVim的安防非常简单,我已经写好了安装脚本,只要执行以下就可以安装,而且不会影响你之前的vim配置,之前的配置都给做了备份,大家看一下脚本就知道备份在哪里了。 +PowerVim的安装非常简单,我已经写好了安装脚本,只要执行以下就可以安装,而且不会影响你之前的vim配置,之前的配置都给做了备份,大家看一下脚本就知道备份在哪里了。 安装过程非常简单: ```bash From aad6b8cee27afa237dca3997fa720705410eac7a Mon Sep 17 00:00:00 2001 From: Logen <47022821+Logenleedev@users.noreply.github.com> Date: Sun, 8 Jan 2023 16:37:47 -0600 Subject: [PATCH 13/21] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BA=86python=20versi?= =?UTF-8?q?on=E7=9A=84=E9=80=BB=E8=BE=91=E3=80=82=E5=81=9A=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=8B=E7=AE=80=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0102.二叉树的层序遍历.md | 2 +- ...38.把二叉搜索树转换为累加树.md | 29 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 406242a7..28425281 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -23,7 +23,7 @@ * 111.二叉树的最小深度 -![我要打十个](https://tva1.sinaimg.cn/large/008eGmZEly1gnadnltbpjg309603w4qp.gif) +![我要打十个](https://tva1.sinaimg.cn/large/008eGmZEly1gPnadnltbpjg309603w4qp.gif) diff --git a/problems/0538.把二叉搜索树转换为累加树.md b/problems/0538.把二叉搜索树转换为累加树.md index ec12c525..d2e98dc8 100644 --- a/problems/0538.把二叉搜索树转换为累加树.md +++ b/problems/0538.把二叉搜索树转换为累加树.md @@ -209,29 +209,28 @@ class Solution { # self.right = right class Solution: def __init__(self): - self.pre = TreeNode() + self.count = 0 def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + if root == None: + return ''' 倒序累加替换: - [2, 5, 13] -> [[2]+[1]+[0], [2]+[1], [2]] -> [20, 18, 13] ''' - self.traversal(root) - return root - - def traversal(self, root: TreeNode) -> None: - # 因为要遍历整棵树,所以递归函数不需要返回值 - # Base Case - if not root: - return None - # 单层递归逻辑:中序遍历的反译 - 右中左 - self.traversal(root.right) # 右 + # 右 + self.convertBST(root.right) + # 中 # 中节点:用当前root的值加上pre的值 - root.val += self.pre.val # 中 - self.pre = root + self.count += root.val - self.traversal(root.left) # 左 + root.val = self.count + + # 左 + self.convertBST(root.left) + + return root + ``` ## Go From 0290d6f1f4170585542eb553ea3def2649af8b54 Mon Sep 17 00:00:00 2001 From: programmercarl <826123027@qq.com> Date: Mon, 9 Jan 2023 16:23:31 +0800 Subject: [PATCH 14/21] Update --- problems/0072.编辑距离.md | 4 - problems/0376.摆动序列.md | 136 ++++++++++++++++++++++++------- problems/0827.最大人工岛.md | 58 +++++++++++-- problems/1020.飞地的数量.md | 4 +- 4 files changed, 161 insertions(+), 41 deletions(-) diff --git a/problems/0072.编辑距离.md b/problems/0072.编辑距离.md index a34439e6..8a877d20 100644 --- a/problems/0072.编辑距离.md +++ b/problems/0072.编辑距离.md @@ -20,24 +20,20 @@ * 输入:word1 = "horse", word2 = "ros" * 输出:3 * 解释: -``` horse -> rorse (将 'h' 替换为 'r') rorse -> rose (删除 'r') rose -> ros (删除 'e') -`` * 示例 2: * 输入:word1 = "intention", word2 = "execution" * 输出:5 * 解释: -``` intention -> inention (删除 't') inention -> enention (将 'i' 替换为 'e') enention -> exention (将 'n' 替换为 'x') exention -> exection (将 'n' 替换为 'c') exection -> execution (插入 'u') -``` 提示: diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index 723d1d9a..35daf301 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -53,21 +53,64 @@ **实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)** -**这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点**。 +**这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点** -本题代码实现中,还有一些技巧,例如统计峰值的时候,数组最左面和最右面是最不好统计的。 +在计算是否有峰值的时候,大家知道遍历的下标i ,计算prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i]),如果`prediff < 0 && curdiff > 0` 或者 `prediff > 0 && curdiff < 0` 此时就有波动就需要统计。 -例如序列[2,5],它的峰值数量是2,如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。 +这是我们思考本题的一个大题思路,但本题要考虑三种情况: -所以可以针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即preDiff = 0,如图: +1. 情况一:相同数字连续 +2. 情况二:数组首尾两端 +3. 情况三:单调坡度有平坡 + +### 情况一:相同数字连续 + +例如 [1,2,2,2,1]这样的数组,如图: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230106170449.png) + +它的摇摆序列长度是多少呢? **其实是长度是3**,也就是我们在删除的时候 要不删除左面的三个2,要不就删除右边的三个2。 + +如图,可以统一规则,删除左边的三个2: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230106172613.png) + +在图中,当i指向第一个2的时候,`prediff > 0 && curdiff = 0` ,当 i 指向最后一个2的时候 `prediff = 0 && curdiff < 0`。 + +如果我们采用,删左面三个2的规则,那么 当 `prediff = 0 && curdiff < 0` 也要记录一个峰值,因为他是把之前相同的元素都删掉留下的峰值。 + +所以我们记录峰值的条件应该是: `(preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)`,为什么这里允许 prediff == 0 ,就是为了 上面我说的这种情况。 + + +### 情况二:数组首尾两端 + + +所以本题统计峰值的时候,数组最左面和最右面如果统计呢? + +题目中说了,如果只有两个不同的元素,那摆动序列也是2。 + +例如序列[2,5],如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。 + +因为我们在计算 prediff(nums[i] - nums[i-1]) 和 curdiff(nums[i+1] - nums[i])的时候,至少需要三个数字才能计算,而数组只有两个数字。 + +这里我们可以写死,就是 如果只有两个元素,且元素不同,那么结果为2。 + +不写死的话,如果和我们的判断规则结合在一起呢? + +可以假设,数组最前面还有一个数字,那这个数字应该是什么呢? + +之前我们在 讨论 情况一:相同数字连续 的时候, prediff = 0 ,curdiff < 0 或者 >0 也记为波谷。 + +那么为了规则统一,针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即preDiff = 0,如图: ![376.摆动序列1](https://img-blog.csdnimg.cn/20201124174357612.png) 针对以上情形,result初始为1(默认最右面有一个峰值),此时curDiff > 0 && preDiff <= 0,那么result++(计算了左面的峰值),最后得到的result就是2(峰值个数为2即摆动序列长度为2) -C++代码如下(和上图是对应的逻辑): +经过以上分析后,我们可以写出如下代码: -```CPP +```CPP +// 版本一 class Solution { public: int wiggleMaxLength(vector& nums) { @@ -78,9 +121,54 @@ public: for (int i = 0; i < nums.size() - 1; i++) { curDiff = nums[i + 1] - nums[i]; // 出现峰值 - if ((curDiff > 0 && preDiff <= 0) || (preDiff >= 0 && curDiff < 0)) { + if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) { result++; - preDiff = curDiff; + } + preDiff = curDiff; + } + return result; + } +}; +``` +* 时间复杂度:O(n) +* 空间复杂度:O(1) + +此时大家是不是发现 以上代码提交也不能通过本题? + +所以此时我们要讨论情况三! + +### 情况三:单调坡度有平坡 + +在版本一中,我们忽略了一种情况,即 如果在一个单调坡度上有平坡,例如[1,2,2,2,3,4],如图: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230108171505.png) + +图中,我们可以看出,版本一的代码在三个地方记录峰值,但其实结果因为是2,因为 单调中的平坡 不能算峰值(即摆动)。 + +之所以版本一会出问题,是因为我们事实更新了 prediff。 + +那么我们应该什么时候更新prediff呢? + +我们只需要在 这个坡度 摆动变化的时候,更新prediff就行,这样prediff在 单调区间有平坡的时候 就不会发生变化,造成我们的误判。 + +所以本题的最终代码为: + +```CPP + +// 版本二 +class Solution { +public: + int wiggleMaxLength(vector& nums) { + if (nums.size() <= 1) return nums.size(); + int curDiff = 0; // 当前一对差值 + int preDiff = 0; // 前一对差值 + int result = 1; // 记录峰值个数,序列默认序列最右边有一个峰值 + for (int i = 0; i < nums.size() - 1; i++) { + curDiff = nums[i + 1] - nums[i]; + // 出现峰值 + if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) { + result++; + preDiff = curDiff; // 注意这里,只在摆动变化的时候更新prediff } } return result; @@ -88,8 +176,11 @@ public: }; ``` -* 时间复杂度:O(n) -* 空间复杂度:O(1) +其实本题看起来好像简单,但需要考虑的情况还是很复杂的,而且很难一次性想到位。 + +**本题异常情况的本质,就是要考虑平坡**, 平坡分两种,一个是 上下中间有平坡,一个是单调有平坡,如图: + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230108174452.png) ## 思路2(动态规划) @@ -111,25 +202,19 @@ public: C++代码如下: -```c++ +```CPP class Solution { public: int dp[1005][2]; int wiggleMaxLength(vector& nums) { memset(dp, 0, sizeof dp); dp[0][0] = dp[0][1] = 1; - - for (int i = 1; i < nums.size(); ++i) - { + for (int i = 1; i < nums.size(); ++i) { dp[i][0] = dp[i][1] = 1; - - for (int j = 0; j < i; ++j) - { + for (int j = 0; j < i; ++j) { if (nums[j] > nums[i]) dp[i][1] = max(dp[i][1], dp[j][0] + 1); } - - for (int j = 0; j < i; ++j) - { + for (int j = 0; j < i; ++j) { if (nums[j] < nums[i]) dp[i][0] = max(dp[i][0], dp[j][1] + 1); } } @@ -153,17 +238,6 @@ public: 空间复杂度:O(n) -## 总结 - -**贪心的题目说简单有的时候就是常识,说难就难在都不知道该怎么用贪心**。 - -本题大家如果要去模拟删除元素达到最长摆动子序列的过程,那指定绕里面去了,一时半会拔不出来。 - -而这道题目有什么技巧说一下子能想到贪心么? - -其实也没有,类似的题目做过了就会想到。 - -此时大家就应该了解了:保持区间波动,只需要把单调区间上的元素移除就可以了。 diff --git a/problems/0827.最大人工岛.md b/problems/0827.最大人工岛.md index fb0c797e..05d82f7e 100644 --- a/problems/0827.最大人工岛.md +++ b/problems/0827.最大人工岛.md @@ -3,8 +3,11 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ # 827. 最大人工岛 +[力扣链接](https://leetcode.cn/problems/making-a-large-island/) + 给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。 返回执行此操作后,grid 中最大的岛屿面积是多少? @@ -30,7 +33,9 @@ 本题的一个暴力想法,应该是遍历地图尝试 将每一个 0 改成1,然后去搜索地图中的最大的岛屿面积。 -计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n +计算地图的最大面积:遍历地图 + 深搜岛屿,时间复杂度为 n * n。 + +(其实使用深搜还是广搜都是可以的,其目的就是遍历岛屿做一个标记,相当于染色,那么使用哪个遍历方式都行,以下我用深搜来讲解) 每改变一个0的方格,都需要重新计算一个地图的最大面积,所以 整体时间复杂度为:n^4。 @@ -41,7 +46,7 @@ 其实每次深搜遍历计算最大岛屿面积,我们都做了很多重复的工作。 -只要把深搜就可以并每个岛屿的面积记录下来就好。 +只要用一次深搜把每个岛屿的面积记录下来就好。 第一步:一次遍历地图,得出各个岛屿的面积,并做编号记录。可以使用map记录,key为岛屿编号,value为岛屿面积 第二步:在遍历地图,遍历0的方格(因为要将0变成1),并统计该1(由0变成的1)周边岛屿面积,将其相邻面积相加在一起,遍历所有 0 之后,就可以得出 选一个0变成1 之后的最大面积。 @@ -74,7 +79,7 @@ void dfs(vector>& grid, vector>& visited, int x, int y, int largestIsland(vector>& grid) { int n = grid.size(), m = grid[0].size(); - vector> visited = vector>(n, vector(m, false)); + vector> visited = vector>(n, vector(m, false)); // 标记访问过的点 unordered_map gridNum; int mark = 2; // 记录每个岛屿的编号 bool isAllGrid = true; // 标记是否整个地图都是陆地 @@ -92,9 +97,10 @@ int largestIsland(vector>& grid) { } ``` + 这个过程时间复杂度 n * n 。可能有录友想:分明是两个for循环下面套这一个dfs,时间复杂度怎么回事 n * n呢? -其实大家可以自己看代码的时候,**n * n这个方格地图中,每个节点我们就遍历一次,并不会重复遍历**。 +其实大家可以仔细看一下代码,**n * n这个方格地图中,每个节点我们就遍历一次,并不会重复遍历**。 第二步过程如图所示: @@ -106,6 +112,47 @@ int largestIsland(vector>& grid) { 所以整个解法的时间复杂度,为 n * n + n * n 也就是 n^2。 +当然这里还有一个优化的点,就是 可以不用 visited数组,因为有mark来标记,所以遍历过的grid[i][j]是不等于1的。 + +代码如下: + +```CPP + int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1}; // 四个方向 + void dfs(vector>& grid, int x, int y, int mark) { + if (grid[x][y] != 1 || grid[x][y] == 0) return; // 终止条件:访问过的节点 或者 遇到海水 + grid[x][y] = mark; // 给陆地标记新标签 + count++; + for (int i = 0; i < 4; i++) { + int nextx = x + dir[i][0]; + int nexty = y + dir[i][1]; + if (nextx < 0 || nextx >= grid.size() || nexty < 0 || nexty >= grid[0].size()) continue; // 越界了,直接跳过 + dfs(grid, nextx, nexty, mark); + } + } + +public: + int largestIsland(vector>& grid) { + int n = grid.size(), m = grid[0].size(); + unordered_map gridNum; + int mark = 2; // 记录每个岛屿的编号 + bool isAllGrid = true; // 标记是否整个地图都是陆地 + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + if (grid[i][j] == 0) isAllGrid = false; + if (grid[i][j] == 1) { + count = 0; + dfs(grid, i, j, mark); // 将与其链接的陆地都标记上 true + gridNum[mark] = count; // 记录每一个岛屿的面积 + mark++; // 记录下一个岛屿编号 + } + } + } + } +} +``` + +不过为了让各个变量各司其事,代码清晰一些,完整代码还是使用visited数组来标记。 + 最后,整体代码如下: ```CPP @@ -129,7 +176,7 @@ private: public: int largestIsland(vector>& grid) { int n = grid.size(), m = grid[0].size(); - vector> visited = vector>(n, vector(m, false)); + vector> visited = vector>(n, vector(m, false)); // 标记访问过的点 unordered_map gridNum; int mark = 2; // 记录每个岛屿的编号 bool isAllGrid = true; // 标记是否整个地图都是陆地 @@ -171,6 +218,7 @@ public: } }; ``` +

diff --git a/problems/1020.飞地的数量.md b/problems/1020.飞地的数量.md index 8b54d7f1..b7cba7a6 100644 --- a/problems/1020.飞地的数量.md +++ b/problems/1020.飞地的数量.md @@ -6,6 +6,8 @@ # 1020. 飞地的数量 +[力扣链接](https://leetcode.cn/problems/number-of-enclaves/description/) + 给你一个大小为 m x n 的二进制矩阵 grid ,其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相邻(上、下、左、右)的陆地单元格或跨过 grid 的边界。 @@ -26,7 +28,7 @@ ## 思路 -本题使用dfs,bfs,并查集都是可以的。 本题和 417. 太平洋大西洋水流问题 很像。 +本题使用dfs,bfs,并查集都是可以的。 本题要求找到不靠边的陆地面积,那么我们只要从周边找到陆地然后 通过 dfs或者bfs 将周边靠陆地且相邻的陆地都变成海洋,然后再去重新遍历地图的时候,统计此时还剩下的陆地就可以了。 From 67b7c7f2b802feb27acb5a33221faa96bc8f03c2 Mon Sep 17 00:00:00 2001 From: ZerenZhang2022 <118794589+ZerenZhang2022@users.noreply.github.com> Date: Mon, 9 Jan 2023 17:27:48 -0500 Subject: [PATCH 15/21] =?UTF-8?q?Update=200093.=E5=A4=8D=E5=8E=9FIP?= =?UTF-8?q?=E5=9C=B0=E5=9D=80.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 加入了bilibili视频链接 --- problems/0093.复原IP地址.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 97178cd5..124b365f 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -40,6 +40,9 @@ * 0 <= s.length <= 3000 * s 仅由数字组成 +# 算法公开课 + +**《代码随想录》算法视频公开课:[93.复原IP地址](https://www.bilibili.com/video/BV1XP4y1U73i/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 # 思路 From 5bd02484387de4c317cfeb114cf1de6b04464aca Mon Sep 17 00:00:00 2001 From: ZerenZhang2022 <118794589+ZerenZhang2022@users.noreply.github.com> Date: Mon, 9 Jan 2023 18:10:32 -0500 Subject: [PATCH 16/21] =?UTF-8?q?Update=200093.=E5=A4=8D=E5=8E=9FIP?= =?UTF-8?q?=E5=9C=B0=E5=9D=80.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 加入了python3,更类似于LeetCode131题代码的写法,看起来更简洁些 --- problems/0093.复原IP地址.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 97178cd5..4e32af99 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -424,6 +424,30 @@ class Solution: return True ``` +python3; 简单拼接版本(类似Leetcode131写法): +```python +class Solution: + def restoreIpAddresses(self, s: str) -> List[str]: + global results, path + results = [] + path = [] + self.backtracking(s,0) + return results + + def backtracking(self,s,index): + global results,path + if index == len(s) and len(path)==4: + results.append('.'.join(path)) # 在连接时需要中间间隔符号的话就在''中间写上对应的间隔符 + return + for i in range(index,len(s)): + if len(path)>3: break # 剪枝 + temp = s[index:i+1] + if (int(temp)<256 and int(temp)>0 and temp[0]!='0') or (temp=='0'): + path.append(temp) + self.backtracking(s,i+1) + path.pop() +``` + ## Go ```go From a7afca36d7024051df6b4614d9028409d5bb1bb5 Mon Sep 17 00:00:00 2001 From: programmercarl <826123027@qq.com> Date: Tue, 10 Jan 2023 09:42:52 +0800 Subject: [PATCH 17/21] Update --- problems/0376.摆动序列.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/problems/0376.摆动序列.md b/problems/0376.摆动序列.md index 35daf301..efb9c6b6 100644 --- a/problems/0376.摆动序列.md +++ b/problems/0376.摆动序列.md @@ -59,11 +59,11 @@ 这是我们思考本题的一个大题思路,但本题要考虑三种情况: -1. 情况一:相同数字连续 +1. 情况一:上下坡中有平坡 2. 情况二:数组首尾两端 -3. 情况三:单调坡度有平坡 +3. 情况三:单调坡中有平坡 -### 情况一:相同数字连续 +### 情况一:上下坡中有平坡 例如 [1,2,2,2,1]这样的数组,如图: @@ -145,7 +145,7 @@ public: 图中,我们可以看出,版本一的代码在三个地方记录峰值,但其实结果因为是2,因为 单调中的平坡 不能算峰值(即摆动)。 -之所以版本一会出问题,是因为我们事实更新了 prediff。 +之所以版本一会出问题,是因为我们实时更新了 prediff。 那么我们应该什么时候更新prediff呢? From a8339121e6f98e9b5241169aef93a04b7ca2ad87 Mon Sep 17 00:00:00 2001 From: Logen <47022821+Logenleedev@users.noreply.github.com> Date: Wed, 11 Jan 2023 13:08:06 -0600 Subject: [PATCH 18/21] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0455.分发饼干.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index eec471af..0a85d04a 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -148,7 +148,7 @@ class Solution { ### Python ```python class Solution: - # 思路1:优先考虑胃饼干 + # 思路1:优先考虑小胃口 def findContentChildren(self, g: List[int], s: List[int]) -> int: g.sort() s.sort() @@ -160,7 +160,7 @@ class Solution: ``` ```python class Solution: - # 思路2:优先考虑胃口 + # 思路2:优先考虑大胃口 def findContentChildren(self, g: List[int], s: List[int]) -> int: g.sort() s.sort() From 91f3da4b43f44d60a0f7c60436ec30869788ec04 Mon Sep 17 00:00:00 2001 From: Logen <47022821+Logenleedev@users.noreply.github.com> Date: Fri, 13 Jan 2023 12:53:05 -0600 Subject: [PATCH 19/21] add Python solution --- ...序与后序遍历序列构造二叉树.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index f8109f85..c2b2872b 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -397,6 +397,9 @@ public: }; ``` +## Python + + # 105.从前序与中序遍历序列构造二叉树 [力扣题目链接](https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) @@ -650,6 +653,37 @@ class Solution { ``` ## Python +```python +class Solution: + def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]: + # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件 + if not postorder: + return + + # 第二步: 后序遍历的最后一个就是当前的中间节点 + root_val = postorder[-1] + root = TreeNode(root_val) + + # 第三步: 找切割点. + root_index = inorder.index(root_val) + + # 第四步: 切割inorder数组. 得到inorder数组的左,右半边. + left_inorder = inorder[:root_index] + right_inorder = inorder[root_index + 1:] + + # 第五步: 切割postorder数组. 得到postorder数组的左,右半边. + # ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的. + left_postorder = postorder[:len(left_inorder)] + right_postorder = postorder[len(left_inorder): len(postorder) - 1] + + + # 第六步: 递归 + root.left = self.buildTree(left_inorder, left_postorder) + root.right = self.buildTree(right_inorder, right_postorder) + + # 第七步: 返回答案 + return root +``` 105.从前序与中序遍历序列构造二叉树 From 1a44d7e7dfd032cf13a42ee4998b6445077c5ebb Mon Sep 17 00:00:00 2001 From: Logen <47022821+Logenleedev@users.noreply.github.com> Date: Sun, 15 Jan 2023 16:34:26 -0600 Subject: [PATCH 20/21] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E5=88=AB?= =?UTF-8?q?=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problems/0134.加油站.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/0134.加油站.md b/problems/0134.加油站.md index ade84773..192e58a6 100644 --- a/problems/0134.加油站.md +++ b/problems/0134.加油站.md @@ -88,7 +88,7 @@ public: * 情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的 * 情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。 -* 情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点。 +* 情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能把这个负数填平,能把这个负数填平的节点就是出发节点。 C++代码如下: From d52112c4555c1db8d2f5037d18c10103531c145b Mon Sep 17 00:00:00 2001 From: programmercarl <826123027@qq.com> Date: Tue, 17 Jan 2023 11:32:18 +0800 Subject: [PATCH 21/21] Update --- problems/0045.跳跃游戏II.md | 6 ++-- problems/0053.最大子序和.md | 28 ++++++++++++--- problems/0055.跳跃游戏.md | 2 +- problems/0130.被围绕的区域.md | 1 + problems/0455.分发饼干.md | 35 ++++++++++++++++--- ...1005.K次取反后最大化的数组和.md | 2 +- problems/1020.飞地的数量.md | 5 +++ 7 files changed, 65 insertions(+), 14 deletions(-) diff --git a/problems/0045.跳跃游戏II.md b/problems/0045.跳跃游戏II.md index 05ad872b..7dbf531b 100644 --- a/problems/0045.跳跃游戏II.md +++ b/problems/0045.跳跃游戏II.md @@ -73,11 +73,11 @@ public: for (int i = 0; i < nums.size(); i++) { nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖最远距离下标 if (i == curDistance) { // 遇到当前覆盖最远距离下标 - if (curDistance != nums.size() - 1) { // 如果当前覆盖最远距离下标不是终点 + if (curDistance < nums.size() - 1) { // 如果当前覆盖最远距离下标不是终点 ans++; // 需要走下一步 curDistance = nextDistance; // 更新当前覆盖最远距离下标(相当于加油了) if (nextDistance >= nums.size() - 1) break; // 下一步的覆盖范围已经可以达到终点,结束循环 - } else break; // 当前覆盖最远距离下标是集合终点,不用做ans++操作了,直接结束 + } else break; // 当前覆盖最远距到达集合终点,不用做ans++操作了,直接结束 } } return ans; @@ -126,7 +126,7 @@ public: 可以看出版本二的代码相对于版本一简化了不少! -其精髓在于控制移动下标i只移动到nums.size() - 2的位置,所以移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不用考虑别的了。 +**其精髓在于控制移动下标i只移动到nums.size() - 2的位置**,所以移动下标只要遇到当前覆盖最远距离的下标,直接步数加一,不用考虑别的了。 ## 总结 diff --git a/problems/0053.最大子序和.md b/problems/0053.最大子序和.md index 665710a9..14017f98 100644 --- a/problems/0053.最大子序和.md +++ b/problems/0053.最大子序和.md @@ -12,9 +12,9 @@ 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 示例: -输入: [-2,1,-3,4,-1,2,1,-5,4] -输出: 6 -解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 +* 输入: [-2,1,-3,4,-1,2,1,-5,4] +* 输出: 6 +* 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 ## 暴力解法 @@ -103,8 +103,28 @@ public: 当然题目没有说如果数组为空,应该返回什么,所以数组为空的话返回啥都可以了。 + +## 常见误区 + +误区一: + 不少同学认为 如果输入用例都是-1,或者 都是负数,这个贪心算法跑出来的结果是0, 这是**又一次证明脑洞模拟不靠谱的经典案例**,建议大家把代码运行一下试一试,就知道了,也会理解 为什么 result 要初始化为最小负数了。 + +误区二: + +大家在使用贪心算法求解本题,经常陷入的误区,就是分不清,是遇到 负数就选择起始位置,还是连续和为负选择起始位置。 + +在动画演示用,大家可以发现, 4,遇到 -1 的时候,我们依然累加了,为什么呢? + +因为和为3,只要连续和还是正数就会 对后面的元素 起到增大总和的作用。 所以只要连续和为正数我们就保留。 + +这里也会有录友疑惑,那 4 + -1 之后 不就变小了吗? 会不会错过 4 成为最大连续和的可能性? + +其实并不会,因为还有一个变量result 一直在更新 最大的连续和,只要有更大的连续和出现,result就更新了,那么result已经把4更新了,后面 连续和变成3,也不会对最后结果有影响。 + + + ## 动态规划 当然本题还可以用动态规划来做,当前[「代码随想录」](https://img-blog.csdnimg.cn/20201124161234338.png)主要讲解贪心系列,后续到动态规划系列的时候会详细讲解本题的dp方法。 @@ -135,7 +155,7 @@ public: 本题的贪心思路其实并不好想,这也进一步验证了,别看贪心理论很直白,有时候看似是常识,但贪心的题目一点都不简单! -后续将介绍的贪心题目都挺难的,哈哈,所以贪心很有意思,别小看贪心! +后续将介绍的贪心题目都挺难的,所以贪心很有意思,别小看贪心! ## 其他语言版本 diff --git a/problems/0055.跳跃游戏.md b/problems/0055.跳跃游戏.md index 7584e952..7b02075b 100644 --- a/problems/0055.跳跃游戏.md +++ b/problems/0055.跳跃游戏.md @@ -78,7 +78,7 @@ public: 一些同学可能感觉,我在讲贪心系列的时候,题目和题目之间貌似没有什么联系? -**是真的就是没什么联系,因为贪心无套路!**没有个整体的贪心框架解决一系列问题,只能是接触各种类型的题目锻炼自己的贪心思维! +**是真的就是没什么联系,因为贪心无套路**!没有个整体的贪心框架解决一系列问题,只能是接触各种类型的题目锻炼自己的贪心思维! ## 其他语言版本 diff --git a/problems/0130.被围绕的区域.md b/problems/0130.被围绕的区域.md index 528d2042..c2aa5696 100644 --- a/problems/0130.被围绕的区域.md +++ b/problems/0130.被围绕的区域.md @@ -83,6 +83,7 @@ public: ``` ## 其他语言版本 +

diff --git a/problems/0455.分发饼干.md b/problems/0455.分发饼干.md index eec471af..8b05735c 100644 --- a/problems/0455.分发饼干.md +++ b/problems/0455.分发饼干.md @@ -52,6 +52,7 @@ C++代码整体如下: ```CPP +// 版本一 // 时间复杂度:O(nlogn) // 空间复杂度:O(1) class Solution { @@ -61,8 +62,8 @@ public: sort(s.begin(), s.end()); int index = s.size() - 1; // 饼干数组的下标 int result = 0; - for (int i = g.size() - 1; i >= 0; i--) { - if (index >= 0 && s[index] >= g[i]) { + for (int i = g.size() - 1; i >= 0; i--) { // 遍历胃口 + if (index >= 0 && s[index] >= g[i]) { // 遍历饼干 result++; index--; } @@ -76,6 +77,26 @@ public: 有的同学看到要遍历两个数组,就想到用两个for循环,那样逻辑其实就复杂了。 + +### 注意事项 + +注意版本一的代码中,可以看出来,是先遍历的胃口,在遍历的饼干,那么可不可以 先遍历 饼干,在遍历胃口呢? + +其实是不可以的。 + +外面的for 是里的下标i 是固定移动的,而if里面的下标 index 是符合条件才移动的。 + +如果 for 控制的是饼干, if 控制胃口,就是出现如下情况 : + +![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230112102848.png) + +if 里的 index 指向 胃口 10, for里的i指向饼干9,因为 饼干9 满足不了 胃口10,所以 i 持续向前移动,而index 走不到` s[index] >= g[i]` 的逻辑,所以index不会移动,那么当i 持续向前移动,最后所有的饼干都匹配不上。 + +所以 一定要for 控制 胃口,里面的if控制饼干。 + + +### 其他思路 + **也可以换一个思路,小饼干先喂饱小胃口** 代码如下: @@ -87,15 +108,19 @@ public: sort(g.begin(),g.end()); sort(s.begin(),s.end()); int index = 0; - for(int i = 0;i < s.size();++i){ - if(index < g.size() && g[index] <= s[i]){ + for(int i = 0; i < s.size(); i++) { // 饼干 + if(index < g.size() && g[index] <= s[i]){ // 胃口 index++; } } return index; } }; -``` +``` + +细心的录友可以发现,这种写法,两个循环的顺序改变了,先遍历的饼干,在遍历的胃口,这是因为遍历顺序变了,我们是从小到大遍历。 + +理由在上面 “注意事项”中 已经讲过。 ## 总结 diff --git a/problems/1005.K次取反后最大化的数组和.md b/problems/1005.K次取反后最大化的数组和.md index 08848a01..cdf42511 100644 --- a/problems/1005.K次取反后最大化的数组和.md +++ b/problems/1005.K次取反后最大化的数组和.md @@ -44,7 +44,7 @@ 那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让 数组和 达到最大。 -那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个 数组和 达到最大。 +那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值和可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个 数组和 达到最大。 虽然这道题目大家做的时候,可能都不会去想什么贪心算法,一鼓作气,就AC了。 diff --git a/problems/1020.飞地的数量.md b/problems/1020.飞地的数量.md index b7cba7a6..3da37376 100644 --- a/problems/1020.飞地的数量.md +++ b/problems/1020.飞地的数量.md @@ -144,6 +144,11 @@ public: } }; ``` +## 类似题目 + +* 1254. 统计封闭岛屿的数目 + +