Update
@ -169,6 +169,10 @@
|
||||
* [回溯算法:解数独](https://mp.weixin.qq.com/s/eWE9TapVwm77yW9Q81xSZQ)
|
||||
* [一篇总结带你彻底搞透回溯算法!](https://mp.weixin.qq.com/s/r73thpBnK1tXndFDtlsdCQ)
|
||||
|
||||
* 贪心算法
|
||||
* [关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)
|
||||
* [贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw)
|
||||
|
||||
|
||||
(持续更新中....)
|
||||
|
||||
|
BIN
pics/.DS_Store
vendored
Normal file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 123 KiB |
BIN
pics/222.完全二叉树的节点个数1.png
Normal file
After Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 2.6 MiB |
BIN
pics/55.跳跃游戏.png
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 44 KiB |
@ -1,5 +1,7 @@
|
||||
> 解数独,理解二维递归是关键
|
||||
|
||||
如果对回溯法理论还不清楚的同学,可以先看这个视频[视频来了!!带你学透回溯算法(理论篇)](https://mp.weixin.qq.com/s/wDd5azGIYWjbU0fdua_qBg)
|
||||
|
||||
# 37. 解数独
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/sudoku-solver/
|
||||
@ -207,3 +209,7 @@ public:
|
||||
|
||||
如果一直跟住「代码随想录」的节奏,你会发现自己进步飞快,从思维方式到刷题习惯,都会有质的飞跃,「代码随想录」绝对值得推荐给身边的同学朋友们!
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
> 开始排列问题
|
||||
> 通知:现在已经将所有历史文章,汇总到一起,有一个整体的目录,方便录友们从前面系列开始卡了,就在公众号左下角「算法汇总」,大家去瞅瞅哈
|
||||
|
||||
# 46.全排列
|
||||
|
||||
@ -32,7 +31,7 @@
|
||||
|
||||
我以[1,2,3]为例,抽象成树形结构如下:
|
||||
|
||||
<img src='../pics/46.全排列.png' width=600> </img></div>
|
||||

|
||||
|
||||
## 回溯三部曲
|
||||
|
||||
@ -44,7 +43,7 @@
|
||||
|
||||
但排列问题需要一个used数组,标记已经选择的元素,如图橘黄色部分所示:
|
||||
|
||||
<img src='../pics/46.全排列.png' width=600> </img></div>
|
||||

|
||||
|
||||
代码如下:
|
||||
|
||||
@ -56,7 +55,7 @@ void backtracking (vector<int>& nums, vector<bool>& used)
|
||||
|
||||
* 递归终止条件
|
||||
|
||||
<img src='../pics/46.全排列.png' width=600> </img></div>
|
||||

|
||||
|
||||
可以看出叶子节点,就是收割结果的地方。
|
||||
|
||||
@ -140,3 +139,7 @@ public:
|
||||
|
||||
就酱,如果感觉「代码随想录」诚意满满,就帮Carl宣传一波吧!
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
> 排列也要去重了
|
||||
> 通知:很多录友都反馈之前看「算法汇总」的目录要一直往下拉,很麻烦,这次Carl将所有历史文章汇总到一篇文章中,有一个整体的目录,方便录友们从前面系列开始卡了,依然在公众号左下角[「算法汇总」](https://mp.weixin.qq.com/s/weyitJcVHBgFtSc19cbPdw),这里会持续更新,大家快去瞅瞅哈
|
||||
|
||||
# 47.全排列 II
|
||||
|
||||
@ -37,7 +36,7 @@
|
||||
|
||||
我以示例中的 [1,1,2]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:
|
||||
|
||||
<img src='../pics/47.全排列II1.png' width=600> </img></div>
|
||||

|
||||
|
||||
图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。
|
||||
|
||||
@ -114,11 +113,11 @@ if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) {
|
||||
|
||||
树层上去重(used[i - 1] == false),的树形结构如下:
|
||||
|
||||
<img src='../pics/47.全排列II2.png' width=600> </img></div>
|
||||

|
||||
|
||||
树枝上去重(used[i - 1] == true)的树型结构如下:
|
||||
|
||||
<img src='../pics/47.全排列II3.png' width=600> </img></div>
|
||||

|
||||
|
||||
大家应该很清晰的看到,树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。
|
||||
|
||||
@ -145,3 +144,7 @@ if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) {
|
||||
|
||||
就酱,很多录友表示和「代码随想录」相见恨晚,那么大家帮忙多多宣传,让更多的同学知道这里,感谢啦!
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
@ -228,3 +228,7 @@ public:
|
||||
|
||||
就酱,如果感觉「代码随想录」干货满满,就分享给身边的朋友同学吧,他们可能也需要!
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
@ -1,25 +1,49 @@
|
||||
## 链接
|
||||
https://leetcode-cn.com/problems/jump-game/
|
||||
|
||||
## 思路
|
||||
# 55. 跳跃游戏
|
||||
|
||||
其实贪心和动态规划很容易混在一起,在面试中,我们应该本着能用贪心就用贪心,贪心解决不了再考虑用动态规划。 毕竟贪心更容易理解,并快速写出代码。
|
||||
给定一个非负整数数组,你最初位于数组的第一个位置。
|
||||
|
||||
数组中的每个元素代表你在该位置可以跳跃的最大长度。
|
||||
|
||||
判断你是否能够到达最后一个位置。
|
||||
|
||||
示例 1:
|
||||
输入: [2,3,1,1,4]
|
||||
输出: true
|
||||
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
|
||||
|
||||
示例 2:
|
||||
输入: [3,2,1,0,4]
|
||||
输出: false
|
||||
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
|
||||
|
||||
|
||||
## 思路
|
||||
|
||||
刚看到本题一开始可能想:当前位置元素如果是3,我究竟是跳一步呢,还是两步呢,还是三步呢,究竟跳几步才是最优呢?
|
||||
|
||||
其实如果本题是要求只能跳元素数值大小的个数,不能多也不能少,问是否达到终点,那么一定要用动态规划了。
|
||||
可以转变一下思路,不一样非要明确一次究竟跳几步,每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。
|
||||
|
||||
这个范围内,已经是可以跳过来的,别管是怎么跳的,反正一定可以跳过来。
|
||||
|
||||
**那么就是这个跳跃覆盖范围究竟可不可以覆盖到终点!**
|
||||
|
||||
每次移动取最大跳跃步数,得到最大的覆盖范围,每移动一个单位,就更新最大覆盖范围。
|
||||
|
||||
**局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到就是整体最大覆盖范围,看是否能到终点**。
|
||||
|
||||
但本题其实我们就看跳到的范围能否覆盖终点,就可以了。
|
||||
|
||||
那么我们每次取最大的覆盖范围,看最后能否覆盖终点。
|
||||
|
||||
如图:
|
||||
|
||||
<img src='../pics/55.跳跃游戏.png' width=600> </img></div>
|
||||

|
||||
|
||||
那么i每次移动只能在cover的范围内移动,每移动一个元素,cover得到该元素数值的补充,让i继续移动下去。
|
||||
i每次移动只能在cover的范围内移动,每移动一个元素,cover得到该元素数值(新的覆盖范围)的补充,让i继续移动下去。
|
||||
|
||||
而cover每次只取 得到该元素数值补充后的范围 和 cover本身范围 的最大值。
|
||||
而cover每次只取 max(该元素数值补充后的范围, cover本身范围)。
|
||||
|
||||
如果cover大于等于了终点下表,直接return true就可以了。
|
||||
|
||||
@ -39,3 +63,8 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
# 总结
|
||||
|
||||
|
||||
|
||||
其实贪心和动态规划很容易混在一起,在面试中,我们应该本着能用贪心就用贪心,贪心解决不了再考虑用动态规划。 毕竟贪心更容易理解,并快速写出代码。
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
用示例中的[1, 2, 2] 来举例,如图所示: (**注意去重需要先对集合排序**)
|
||||
|
||||
<img src='../pics/90.子集II.png' width=600> </img></div>
|
||||

|
||||
|
||||
从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!
|
||||
|
||||
@ -114,16 +114,19 @@ public:
|
||||
|
||||
其实这道题目的知识点,我们之前都讲过了,如果之前讲过的子集问题和去重问题都掌握的好,这道题目应该分分钟AC。
|
||||
|
||||
当然本题去重的逻辑,也可以这么写
|
||||
|
||||
这道题目去重的逻辑,也可以这么写
|
||||
```
|
||||
if (i > startIndex && nums[i] == nums[i - 1] ) {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
```
|
||||
|
||||
**就酱,如果感觉融会贯通了,就把「代码随想录」介绍给自己的同学朋友吧,也许他们也需要!**
|
||||
|
||||
> 我是[程序员Carl](https://github.com/youngyangyang04),组队刷题可以找我,本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),期待你的关注!
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20201124161234338.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉题解对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
## 题目地址
|
||||
https://leetcode-cn.com/problems/count-complete-tree-nodes/
|
||||
|
||||
> 今天是中秋&&国庆,所以来一道二叉树简单题吧
|
||||
|
||||
如果之前两篇[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg), [二叉树:看看这些树的最小深度](https://mp.weixin.qq.com/s/BH8-gPC3_QlqICDg7rGSGA)都认真看了的话,这道题目可以分分钟刷掉了哈哈。
|
||||
|
||||
# 222.完全二叉树的节点个数
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/
|
||||
|
||||
给出一个完全二叉树,求出该树的节点个数。
|
||||
|
||||
示例:
|
||||
@ -15,17 +11,17 @@ https://leetcode-cn.com/problems/count-complete-tree-nodes/
|
||||
|
||||
# 思路
|
||||
|
||||
这道题目其实没有必要强调是完全二叉树,就是求二叉树节点的个数。
|
||||
本篇给出按照普通二叉树的求法以及利用完全二叉树性质的求法。
|
||||
|
||||

|
||||
## 普通二叉树
|
||||
|
||||
依然可以使用递归法和迭代法来解决。
|
||||
首先按照普通二叉树的逻辑来求。
|
||||
|
||||
这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
|
||||
|
||||
递归遍历的顺序依然是后序(左右中)。
|
||||
|
||||
## 递归
|
||||
### 递归
|
||||
|
||||
如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)。
|
||||
|
||||
@ -49,15 +45,16 @@ if (cur == NULL) return 0;
|
||||
代码如下:
|
||||
|
||||
```
|
||||
int leftNum = getNodesNum(cur->left); // 左
|
||||
int rightNum = getNodesNum(cur->right); // 右
|
||||
int treeNum = leftNum + rightNum + 1; // 中
|
||||
return treeNum;
|
||||
int leftNum = getNodesNum(cur->left); // 左
|
||||
int rightNum = getNodesNum(cur->right); // 右
|
||||
int treeNum = leftNum + rightNum + 1; // 中
|
||||
return treeNum;
|
||||
```
|
||||
|
||||
所以整体C++代码如下:
|
||||
|
||||
```
|
||||
// 版本一
|
||||
class Solution {
|
||||
private:
|
||||
int getNodesNum(TreeNode* cur) {
|
||||
@ -76,6 +73,7 @@ public:
|
||||
|
||||
代码精简之后C++代码如下:
|
||||
```
|
||||
// 版本二
|
||||
class Solution {
|
||||
public:
|
||||
int countNodes(TreeNode* root) {
|
||||
@ -83,10 +81,15 @@ public:
|
||||
return 1 + countNodes(root->left) + countNodes(root->right);
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 迭代法
|
||||
时间复杂度:O(n)
|
||||
空间复杂度:O(logn),算上了递归系统栈占用的空间
|
||||
|
||||
**网上基本都是这个精简的代码版本,其实不建议大家照着这个来写,代码确实精简,但隐藏了一些内容,连遍历的顺序都看不出来,所以初学者建议学习版本一的代码,稳稳的打基础**。
|
||||
|
||||
|
||||
### 迭代法
|
||||
|
||||
如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog)。
|
||||
|
||||
@ -113,15 +116,57 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
时间复杂度:O(n)
|
||||
空间复杂度:O(n)
|
||||
|
||||
# 总结
|
||||
## 完全二叉树
|
||||
|
||||
这道题目的解法其实我们在[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/guKwV-gSNbA1CcbvkMtHBg)和 [二叉树:看看这些树的最小深度](https://mp.weixin.qq.com/s/BH8-gPC3_QlqICDg7rGSGA)都有提到过了。
|
||||
以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/_ymfWYvTNd2GvWvC5HOE4A),这篇详细介绍了各种二叉树的特性。
|
||||
|
||||
一样的分析套路,代码也差不多,估计此时大家最这一类求二叉树节点数量以及求深度应该非常熟练了。
|
||||
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
|
||||
|
||||
没有做过这道题目的同学可以愉快的刷了它了。
|
||||
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
|
||||
|
||||
最后祝大家中秋&国庆节日愉快哈!
|
||||
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
|
||||
|
||||
完全二叉树(一)如图:
|
||||

|
||||
|
||||
完全二叉树(二)如图:
|
||||

|
||||
|
||||
可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```C++
|
||||
class Solution {
|
||||
public:
|
||||
int countNodes(TreeNode* root) {
|
||||
if (root == nullptr) return 0;
|
||||
TreeNode* left = root->left;
|
||||
TreeNode* right = root->right;
|
||||
int leftHeight = 0, rightHeight = 0; // 这里初始为0是有目的的,为了下面求指数方便
|
||||
while (left) { // 求左子树深度
|
||||
left = left->left;
|
||||
leftHeight++;
|
||||
}
|
||||
while (right) { // 求右子树深度
|
||||
right = right->right;
|
||||
rightHeight++;
|
||||
}
|
||||
if (leftHeight == rightHeight) {
|
||||
return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0
|
||||
}
|
||||
return countNodes(root->left) + countNodes(root->right) + 1;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
时间复杂度:O(logn * logn)
|
||||
空间复杂度:O(logn)
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
|
||||
|
@ -101,7 +101,7 @@ void backtracking(参数) {
|
||||
|
||||
本题以输入:[["JFK", "KUL"], ["JFK", "NRT"], ["NRT", "JFK"]为例,抽象为树形结构如下:
|
||||
|
||||
<img src='https://img-blog.csdnimg.cn/2020111518065555.png' width=600> </img></div>
|
||||

|
||||
|
||||
开始回溯三部曲讲解:
|
||||
|
||||
@ -127,7 +127,7 @@ bool backtracking(int ticketNum, vector<string>& result) {
|
||||
|
||||
因为我们只需要找到一个行程,就是在树形结构中唯一的一条通向叶子节点的路线,如图:
|
||||
|
||||
<img src='https://img-blog.csdnimg.cn/2020111518065555.png' width=600> </img></div>
|
||||

|
||||
|
||||
所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)详细介绍过。
|
||||
|
||||
@ -246,4 +246,7 @@ for (pair<string, int>target : targets[result[result.size() - 1]])
|
||||
就酱,很多录友表示和「代码随想录」相见恨晚,那么帮Carl宣传一波吧,让更多同学知道这里!
|
||||
|
||||
|
||||
> 更多算法干货文章持续更新,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
@ -1,44 +1,75 @@
|
||||
|
||||
题目链接: https://leetcode-cn.com/problems/wiggle-subsequence/
|
||||
> 本周讲解了[贪心理论基础](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg),以及第一道贪心的题目:[贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。
|
||||
|
||||
# 376. 摆动序列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/wiggle-subsequence/
|
||||
|
||||
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
|
||||
|
||||
例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
|
||||
|
||||
给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
|
||||
|
||||
示例 1:
|
||||
输入: [1,7,4,9,2,5]
|
||||
输出: 6
|
||||
解释: 整个序列均为摆动序列。
|
||||
|
||||
示例 2:
|
||||
输入: [1,17,5,10,13,15,10,5,16,8]
|
||||
输出: 7
|
||||
解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。
|
||||
|
||||
示例 3:
|
||||
输入: [1,2,3,4,5,6,7,8,9]
|
||||
输出: 2
|
||||
|
||||
|
||||
## 思路
|
||||
|
||||
本题要求通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
|
||||
|
||||
相信这么一说吓退不少同学,这又可以修改数组,这得如何修改呢?
|
||||
相信这么一说吓退不少同学,这要求最大摆动序列又可以修改数组,这得如何修改呢?
|
||||
|
||||
我们来分析一下,要求删除元素使其达到最大摆动序列,应该删除什么元素呢?
|
||||
来分析一下,要求删除元素使其达到最大摆动序列,应该删除什么元素呢?
|
||||
|
||||
用示例二来举例,如图所示:
|
||||
|
||||
<img src='../pics/376.摆动序列.png' width=600> </img></div>
|
||||

|
||||
|
||||
图中可以看出,为了让摆动序列最长,只需要把单一坡度(递增或者递减)上的节点删掉就可以了。
|
||||
**局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值**。
|
||||
|
||||
**整体最优:整个序列有最多的局部峰值,从而达到最长摆动序列**。
|
||||
|
||||
局部最优推出全局最优,并举不出反例,那么试试贪心!
|
||||
|
||||
(为方便表述,以下说的峰值都是指局部峰值)
|
||||
|
||||
**实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)**
|
||||
|
||||
**这就是贪心所贪的地方,让峰值尽可能的保持峰值,然后删除单一坡度上的节点**。
|
||||
|
||||
**实际操作上,其实练删除的操作都不用做,因为题目要求的是摆动序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)**
|
||||
本题代码实现中,还有一些技巧,例如统计峰值的时候,数组最左面和最右面是最不好统计的。
|
||||
|
||||
代码实现中,还有一些技巧,例如统计峰值的时候,数组最左面和最右面是最不好统计的。
|
||||
例如序列[2,5],它的峰值数量是2,如果靠统计差值来计算峰值个数就需要考虑数组最左面和最右面的特殊情况。
|
||||
|
||||
例如数组[2,5],它的峰值数量是2,如果靠统计差值来计算峰值就需要考虑数组最左面和最右面的特殊情况。
|
||||
所以可以针对序列[2,5],可以假设为[2,2,5],这样它就有坡度了即preDiff = 0,如图:
|
||||
|
||||
所以可以针对数组[2,5],假设为[2,2,5],这样它就有坡度了,如图:
|
||||

|
||||
|
||||
<img src='../pics/376.摆动序列1.png' width=600> </img></div>
|
||||
|
||||
这样result初始为1,curDiff > 0 && preDiff <= 0,result++,最后得到的result就是2了。
|
||||
针对以上情形,result初始为1(默认最右面有一个峰值),此时curDiff > 0 && preDiff <= 0,那么result++(计算了左面的峰值),最后得到的result就是2(峰值个数为2即摆动序列长度为2)
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```
|
||||
```C++
|
||||
class Solution {
|
||||
public:
|
||||
int wiggleMaxLength(vector<int>& nums) {
|
||||
if (nums.size() <= 1) return nums.size();
|
||||
int curDiff = 0; // 当前一对差值
|
||||
int preDiff = 0; // 前一对差值
|
||||
int result = 1; // 记录峰值,起始位置峰值为1
|
||||
int result = 1; // 记录峰值个数,序列默认序列最右边有一个峰值
|
||||
for (int i = 1; i < nums.size(); i++) {
|
||||
curDiff = nums[i] - nums[i - 1];
|
||||
// 出现峰值
|
||||
@ -51,6 +82,25 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
时间复杂度O(n)
|
||||
空间复杂度O(1)
|
||||
|
||||
# 总结
|
||||
|
||||
**贪心的题目说简单有的时候就是常识,说难就难在都不知道该怎么用贪心**。
|
||||
|
||||
本题大家如果要去模拟删除元素达到最长摆动子序列的过程,那指定绕里面去了,一时半会拔不出来。
|
||||
|
||||
而这道题目有什么技巧说一下子能想到贪心么?
|
||||
|
||||
其实也没有,类似的题目做过了就会想到。
|
||||
|
||||
此时大家就应该了解了:保持区间波动,只需要把单调区间上的元素移除就可以了。
|
||||
|
||||
就酱,「代码随想录」值得介绍给身边每一位学习算法的同学!
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20201124161234338.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉题解对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
> 我是[程序员Carl](https://github.com/youngyangyang04),组队刷题可以找我,本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),期待你的关注!
|
||||
|
||||
|
@ -28,9 +28,9 @@
|
||||
|
||||
|
||||
提示:
|
||||
* 1 <= g.length <= 3 * 104
|
||||
* 0 <= s.length <= 3 * 104
|
||||
* 1 <= g[i], s[j] <= 231 - 1
|
||||
* 1 <= g.length <= 3 * 10^4
|
||||
* 0 <= s.length <= 3 * 10^4
|
||||
* 1 <= g[i], s[j] <= 2^31 - 1
|
||||
|
||||
|
||||
## 思路
|
||||
@ -79,6 +79,29 @@ public:
|
||||
|
||||
有的同学看到要遍历两个数组,就想到用两个for循环,那样逻辑其实就复杂了。
|
||||
|
||||
**也可以换一个思路,小饼干先喂饱小胃口**
|
||||
|
||||
代码如下:
|
||||
|
||||
```
|
||||
class Solution {
|
||||
public:
|
||||
int findContentChildren(vector<int>& g, vector<int>& s) {
|
||||
sort(g.begin(),g.end());
|
||||
sort(s.begin(),s.end());
|
||||
int res = 0;
|
||||
int index = 0;
|
||||
for(int i = 0;i < s.size();++i){
|
||||
if(index < g.size() && g[index] <= s[i]){
|
||||
index++;
|
||||
res++;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
# 总结
|
||||
|
||||
这道题是贪心很好的一道入门题目,思路还是比较容易想到的。
|
||||
@ -87,5 +110,8 @@ public:
|
||||
|
||||
就酱,「代码随想录」值得介绍给身边的朋友同学们!
|
||||
|
||||
> 我是[程序员Carl](https://github.com/youngyangyang04),组队刷题可以找我,本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),期待你的关注!
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉题解对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
## 题目地址
|
||||
|
||||
> 和子集问题有点像,但又处处是陷阱
|
||||
|
||||
@ -37,7 +36,7 @@
|
||||
|
||||
为了有鲜明的对比,我用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:
|
||||
|
||||
<img src='../pics/491. 递增子序列1.png' width=600> </img></div>
|
||||

|
||||
|
||||
|
||||
## 回溯三部曲
|
||||
@ -69,30 +68,8 @@ if (path.size() > 1) {
|
||||
|
||||
* 单层搜索逻辑
|
||||
|
||||
<img src='../pics/491. 递增子序列1.png' width=600> </img></div>
|
||||
在图中可以看出,**同一父节点下的同层上使用过的元素就不能在使用了**,注意这里要求的是**同一父节点下的同层**,这里和[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中去重的有本质区别。
|
||||
|
||||
[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)是要整棵树的同一层进行去重,所以进行排序!
|
||||
|
||||
如图:
|
||||

|
||||
|
||||
**本题只要同一父节点下的同层上重复使用元素,递增子序列就会重复**,而[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中是排序之后看相邻元素是否重复使用。
|
||||
|
||||
|
||||
还有一种情况就是如果选取的元素小于子序列最后一个元素,那么就不能是递增的,所以也要pass掉。
|
||||
|
||||
那么去重的逻辑代码如下:
|
||||
|
||||
```
|
||||
if ((!path.empty() && nums[i] < path.back())
|
||||
|| uset.find(nums[i]) != uset.end()) {
|
||||
continue;
|
||||
}
|
||||
```
|
||||
判断`nums[i] < path.back()`之前一定要判断path是否为空,所以是`!path.empty() && nums[i] < path.back()`。
|
||||
|
||||
`uset.find(nums[i]) != uset.end()`判断nums[i]在本层是否使用过。
|
||||

|
||||
在图中可以看出,**同一父节点下的同层上使用过的元素就不能在使用了**
|
||||
|
||||
那么单层搜索代码如下:
|
||||
|
||||
@ -213,3 +190,7 @@ public:
|
||||
**就酱,如果感觉「代码随想录」很干货,就帮Carl宣传一波吧!**
|
||||
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|
32
problems/0494.目标和.md
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
// 这道题小细节很多
|
||||
// 感觉这道题可以用回溯法啊
|
||||
// 转为01 背包 思路不好想啊
|
||||
// dp数组难在如何初始化
|
||||
// dp 数组 通常比较长
|
||||
```
|
||||
class Solution {
|
||||
public:
|
||||
int findTargetSumWays(vector<int>& nums, int S) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < nums.size(); i++) sum += nums[i];
|
||||
if (S > sum) return 0; // 此时没有方案
|
||||
if ((S + sum) % 2) return 0; // 此时没有方案,两个int相加的时候要各位小心数值溢出的问题
|
||||
|
||||
int bagSize = (S + sum) / 2;
|
||||
int dp[1001] = {1};
|
||||
//for (int i = 0; i < nums.size(); i++) dp[nums[i]] = 1;
|
||||
for (int i = 0; i < nums.size(); i++) {
|
||||
for (int j = bagSize; j >= nums[i]; j--) {
|
||||
if (j - nums[i] >= 0) dp[j] += dp[j - nums[i]];
|
||||
}
|
||||
//for (int k = 0; k <= bagSize; k++) {
|
||||
// cout << dp[k] << " ";
|
||||
//}
|
||||
//cout << endl;
|
||||
}
|
||||
return dp[bagSize];
|
||||
}
|
||||
};
|
||||
```
|
@ -1,5 +1,5 @@
|
||||
|
||||
# 本周小结!(回溯算法系列三)续集 o
|
||||
# 本周小结!(回溯算法系列三)续集
|
||||
|
||||
> 在 [本周小结!(回溯算法系列三)](https://mp.weixin.qq.com/s/tLkt9PSo42X60w8i94ViiA) 中一位录友对 整颗树的本层和同一节点的本层有疑问,也让我重新思考了一下,发现这里确实有问题,所以专门写一篇来纠正,感谢录友们的积极交流哈!
|
||||
|
||||
@ -239,3 +239,7 @@ used数组可是全局变量,每层与每层之间公用一个used数组,所
|
||||
|
||||
就酱,「代码随想录」一直都是干货满满,公众号里的一抹清流,值得推荐给身边的每一位同学朋友!
|
||||
|
||||
> **我是[程序员Carl](https://github.com/youngyangyang04),可以找我[组队刷题](https://img-blog.csdnimg.cn/20201115103410182.png),也可以在[B站上找到我](https://space.bilibili.com/525438321),本文[leetcode刷题攻略](https://github.com/youngyangyang04/leetcode-master)已收录,更多[精彩算法文章](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxNjY5NTYxNA==&action=getalbum&album_id=1485825793120387074&scene=173#wechat_redirect)尽在公众号:[代码随想录](https://img-blog.csdnimg.cn/20200815195519696.png),关注后就会发现和「代码随想录」相见恨晚!**
|
||||
|
||||
**如果感觉对你有帮助,不要吝啬给一个👍吧!**
|
||||
|
||||
|