mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 03:34:02 +08:00
47~541连接更新‘
This commit is contained in:
@ -9,7 +9,7 @@
|
||||
|
||||
## 第51题. N皇后
|
||||
|
||||
题目链接: https://leetcode-cn.com/problems/n-queens/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/n-queens/)
|
||||
|
||||
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 53. 最大子序和
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/maximum-subarray/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/maximum-subarray/)
|
||||
|
||||
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 53. 最大子序和
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/maximum-subarray/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/maximum-subarray/)
|
||||
|
||||
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
这道题之前我们在讲解贪心专题的时候用贪心算法解决过一次,[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg)。
|
||||
这道题之前我们在讲解贪心专题的时候用贪心算法解决过一次,[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html)。
|
||||
|
||||
这次我们用动态规划的思路再来分析一次。
|
||||
|
||||
@ -87,7 +87,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
这道题目用贪心也很巧妙,但有一点绕,需要仔细想一想,如果想回顾一下贪心就看这里吧:[贪心算法:最大子序和](https://mp.weixin.qq.com/s/DrjIQy6ouKbpletQr0g1Fg)
|
||||
这道题目用贪心也很巧妙,但有一点绕,需要仔细想一想,如果想回顾一下贪心就看这里吧:[贪心算法:最大子序和](https://programmercarl.com/0053.最大子序和.html)
|
||||
|
||||
动规的解法还是很直接的。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 55. 跳跃游戏
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/jump-game/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/jump-game/)
|
||||
|
||||
给定一个非负整数数组,你最初位于数组的第一个位置。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 56. 合并区间
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/merge-intervals/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/merge-intervals/)
|
||||
|
||||
给出一个区间的集合,请合并所有重叠的区间。
|
||||
|
||||
@ -126,7 +126,7 @@ public:
|
||||
|
||||
那应该怎么办呢?
|
||||
|
||||
正如我贪心系列开篇词[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中讲解的一样,贪心本来就没有套路,也没有框架,所以各种常规解法需要多接触多练习,自然而然才会想到。
|
||||
正如我贪心系列开篇词[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中讲解的一样,贪心本来就没有套路,也没有框架,所以各种常规解法需要多接触多练习,自然而然才会想到。
|
||||
|
||||
「代码随想录」会把贪心常见的经典题目覆盖到,大家只要认真学习打卡就可以了。
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
## 59.螺旋矩阵II
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/spiral-matrix-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/spiral-matrix-ii/)
|
||||
给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
|
||||
|
||||
示例:
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里哪里有问题,改了那里这里又跑不起来了。
|
||||
|
||||
大家还记得我们在这篇文章[数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/4X-8VRgnYRGd5LYGZ33m4w)中讲解了二分法,提到如果要写出正确的二分法一定要坚持**循环不变量原则**。
|
||||
大家还记得我们在这篇文章[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0704.二分查找.html)中讲解了二分法,提到如果要写出正确的二分法一定要坚持**循环不变量原则**。
|
||||
|
||||
而求解本题依然是要坚持循环不变量原则。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 62.不同路径
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/unique-paths/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/unique-paths/)
|
||||
|
||||
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
示例 4:
|
||||
输入:m = 3, n = 3
|
||||
输出:6
|
||||
|
||||
|
||||
提示:
|
||||
* 1 <= m, n <= 100
|
||||
* 题目数据保证答案小于等于 2 * 10^9
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 63. 不同路径 II
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/unique-paths-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/unique-paths-ii/)
|
||||
|
||||
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
|
||||
|
||||
@ -49,11 +49,11 @@
|
||||
|
||||
## 思路
|
||||
|
||||
这道题相对于[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A) 就是有了障碍。
|
||||
这道题相对于[62.不同路径](https://programmercarl.com/0062.不同路径.html) 就是有了障碍。
|
||||
|
||||
第一次接触这种题目的同学可能会有点懵,这有障碍了,应该怎么算呢?
|
||||
|
||||
[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了。
|
||||
[62.不同路径](https://programmercarl.com/0062.不同路径.html)中我们已经详细分析了没有障碍的情况,有障碍的话,其实就是标记对应的dp table(dp数组)保持初始值(0)就可以了。
|
||||
|
||||
动规五部曲:
|
||||
|
||||
@ -77,7 +77,7 @@ if (obstacleGrid[i][j] == 0) { // 当(i, j)没有障碍的时候,再推导dp[i
|
||||
|
||||
3. dp数组如何初始化
|
||||
|
||||
在[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)不同路径中我们给出如下的初始化:
|
||||
在[62.不同路径](https://programmercarl.com/0062.不同路径.html)不同路径中我们给出如下的初始化:
|
||||
|
||||
```
|
||||
vector<vector<int>> dp(m, vector<int>(n, 0)); // 初始值为0
|
||||
@ -159,7 +159,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
本题是[62.不同路径](https://mp.weixin.qq.com/s/MGgGIt4QCpFMROE9X9he_A)的障碍版,整体思路大体一致。
|
||||
本题是[62.不同路径](https://programmercarl.com/0062.不同路径.html)的障碍版,整体思路大体一致。
|
||||
|
||||
但就算是做过62.不同路径,在做本题也会有感觉遇到障碍无从下手。
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
## 70. 爬楼梯
|
||||
题目地址:https://leetcode-cn.com/problems/climbing-stairs/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/climbing-stairs/)
|
||||
|
||||
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
|
||||
|
||||
@ -196,9 +196,9 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
这道题目和[动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w)题目基本是一样的,但是会发现本题相比[动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w)难多了,为什么呢?
|
||||
这道题目和[动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)题目基本是一样的,但是会发现本题相比[动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html)难多了,为什么呢?
|
||||
|
||||
关键是 [动态规划:斐波那契数](https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w) 题目描述就已经把动规五部曲里的递归公式和如何初始化都给出来了,剩下几部曲也自然而然的推出来了。
|
||||
关键是 [动态规划:斐波那契数](https://programmercarl.com/0509.斐波那契数.html) 题目描述就已经把动规五部曲里的递归公式和如何初始化都给出来了,剩下几部曲也自然而然的推出来了。
|
||||
|
||||
而本题,就需要逐个分析了,大家现在应该初步感受出[关于动态规划,你该了解这些!](https://leetcode-cn.com/circle/article/tNuNnM/)里给出的动规五部曲了。
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
## 70. 爬楼梯
|
||||
|
||||
链接:https://leetcode-cn.com/problems/climbing-stairs/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/climbing-stairs/)
|
||||
|
||||
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
这道题目 我们在[动态规划:爬楼梯](https://mp.weixin.qq.com/s/Ohop0jApSII9xxOMiFhGIw) 中已经讲过一次了,原题其实是一道简单动规的题目。
|
||||
这道题目 我们在[动态规划:爬楼梯](https://programmercarl.com/0070.爬楼梯.html) 中已经讲过一次了,原题其实是一道简单动规的题目。
|
||||
|
||||
既然这么简单为什么还要讲呢,其实本题稍加改动就是一道面试好题。
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
|
||||
**此时大家应该发现这就是一个完全背包问题了!**
|
||||
|
||||
和昨天的题目[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)基本就是一道题了。
|
||||
和昨天的题目[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)基本就是一道题了。
|
||||
|
||||
动规五部曲分析如下:
|
||||
|
||||
@ -62,7 +62,7 @@
|
||||
|
||||
2. 确定递推公式
|
||||
|
||||
在[动态规划:494.目标和](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) 、 [动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)、[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)中我们都讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
|
||||
在[动态规划:494.目标和](https://programmercarl.com/0494.目标和.html) 、 [动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)、[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)中我们都讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
|
||||
|
||||
本题呢,dp[i]有几种来源,dp[i - 1],dp[i - 2],dp[i - 3] 等等,即:dp[i - j]
|
||||
|
||||
@ -84,12 +84,11 @@
|
||||
|
||||
5. 举例来推导dp数组
|
||||
|
||||
介于本题和[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)几乎是一样的,这里我就不再重复举例了。
|
||||
介于本题和[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)几乎是一样的,这里我就不再重复举例了。
|
||||
|
||||
|
||||
以上分析完毕,C++代码如下:
|
||||
|
||||
```cpp
|
||||
```
|
||||
class Solution {
|
||||
public:
|
||||
int climbStairs(int n) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 72. 编辑距离
|
||||
|
||||
https://leetcode-cn.com/problems/edit-distance/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/edit-distance/)
|
||||
|
||||
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
|
||||
|
||||
@ -35,7 +35,7 @@ inention -> enention (将 'i' 替换为 'e')
|
||||
enention -> exention (将 'n' 替换为 'x')
|
||||
exention -> exection (将 'n' 替换为 'c')
|
||||
exection -> execution (插入 'u')
|
||||
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 第77题. 组合
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/combinations/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/combinations/ )
|
||||
|
||||
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
|
||||
|
||||
@ -80,7 +80,7 @@ for (int i = 1; i <= n; i++) {
|
||||
|
||||
如果脑洞模拟回溯搜索的过程,绝对可以让人窒息,所以需要抽象图形结构来进一步理解。
|
||||
|
||||
**我们在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中说道回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。
|
||||
**我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中说道回溯法解决的问题都可以抽象为树形结构(N叉树),用树形结构来理解回溯就容易多了**。
|
||||
|
||||
那么我把组合问题抽象为如下树形结构:
|
||||
|
||||
@ -100,7 +100,7 @@ for (int i = 1; i <= n; i++) {
|
||||
|
||||
相当于只需要把达到叶子节点的结果收集起来,就可以求得 n个数中k个数的组合集合。
|
||||
|
||||
在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中我们提到了回溯法三部曲,那么我们按照回溯法三部曲开始正式讲解代码了。
|
||||
在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中我们提到了回溯法三部曲,那么我们按照回溯法三部曲开始正式讲解代码了。
|
||||
|
||||
|
||||
## 回溯法三部曲
|
||||
@ -214,7 +214,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
还记得我们在[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中给出的回溯法模板么?
|
||||
还记得我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中给出的回溯法模板么?
|
||||
|
||||
如下:
|
||||
```
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
|
||||
在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。
|
||||
在[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)中,我们通过回溯搜索法,解决了n个数中求k个数的组合问题。
|
||||
|
||||
> 可以直接看我的B栈视频讲解:[带你学透回溯算法-组合问题的剪枝操作](https://www.bilibili.com/video/BV1wi4y157er)
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
链接:https://leetcode-cn.com/problems/combinations/
|
||||
|
||||
**看本篇之前,需要先看[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)**。
|
||||
**看本篇之前,需要先看[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)**。
|
||||
|
||||
大家先回忆一下[77. 组合]给出的回溯法的代码:
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 第78题. 子集
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/subsets/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/subsets/)
|
||||
|
||||
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
求子集问题和[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)和[回溯算法:分割问题!](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)又不一样了。
|
||||
求子集问题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:分割问题!](https://programmercarl.com/0131.分割回文串.html)又不一样了。
|
||||
|
||||
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,**那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!**
|
||||
|
||||
@ -101,7 +101,7 @@ for (int i = startIndex; i < nums.size(); i++) {
|
||||
|
||||
## C++代码
|
||||
|
||||
根据[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)给出的回溯算法模板:
|
||||
根据[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)给出的回溯算法模板:
|
||||
|
||||
```
|
||||
void backtracking(参数) {
|
||||
@ -157,15 +157,15 @@ public:
|
||||
|
||||
相信大家经过了
|
||||
* 组合问题:
|
||||
* [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)
|
||||
* [回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)
|
||||
* [回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)
|
||||
* [回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A)
|
||||
* [回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)
|
||||
* [回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)
|
||||
* [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)
|
||||
* [回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)
|
||||
* [回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)
|
||||
* [回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
|
||||
* [回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)
|
||||
* [回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)
|
||||
* 分割问题:
|
||||
* [回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)
|
||||
* [回溯算法:复原IP地址](https://mp.weixin.qq.com/s/v--VmA8tp9vs4bXCqHhBuA)
|
||||
* [回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)
|
||||
* [回溯算法:复原IP地址](https://programmercarl.com/0093.复原IP地址.html)
|
||||
|
||||
洗礼之后,发现子集问题还真的有点简单了,其实这就是一道标准的模板题。
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# 84.柱状图中最大的矩形
|
||||
|
||||
链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/largest-rectangle-in-histogram/)
|
||||
|
||||
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
|
||||
# 思路
|
||||
|
||||
本题和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw),是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!
|
||||
本题和[42. 接雨水](https://programmercarl.com/0042.接雨水.html),是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!
|
||||
|
||||
其实这两道题目先做那一道都可以,但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)
|
||||
其实这两道题目先做那一道都可以,但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:[42. 接雨水](https://programmercarl.com/0042.接雨水.html)
|
||||
|
||||
我们先来看一下双指针的解法:
|
||||
|
||||
@ -50,11 +50,11 @@ public:
|
||||
|
||||
## 动态规划
|
||||
|
||||
本题动态规划的写法整体思路和[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)是一致的,但要比[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)难一些。
|
||||
本题动态规划的写法整体思路和[42. 接雨水](https://programmercarl.com/0042.接雨水.html)是一致的,但要比[42. 接雨水](https://programmercarl.com/0042.接雨水.html)难一些。
|
||||
|
||||
难就难在本题要记录记录每个柱子 左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度。
|
||||
|
||||
所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释,整理思路在题解:[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中已经介绍了。
|
||||
所以需要循环查找,也就是下面在寻找的过程中使用了while,详细请看下面注释,整理思路在题解:[42. 接雨水](https://programmercarl.com/0042.接雨水.html)中已经介绍了。
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
@ -95,11 +95,11 @@ public:
|
||||
|
||||
本地单调栈的解法和接雨水的题目是遥相呼应的。
|
||||
|
||||
为什么这么说呢,[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。
|
||||
为什么这么说呢,[42. 接雨水](https://programmercarl.com/0042.接雨水.html)是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。
|
||||
|
||||
**这里就涉及到了单调栈很重要的性质,就是单调栈里的顺序,是从小到大还是从大到小**。
|
||||
|
||||
在题解[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
|
||||
在题解[42. 接雨水](https://programmercarl.com/0042.接雨水.html)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
|
||||
|
||||
那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!
|
||||
|
||||
@ -115,7 +115,7 @@ public:
|
||||
|
||||
理解这一点,对单调栈就掌握的比较到位了。
|
||||
|
||||
除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解[42. 接雨水](https://mp.weixin.qq.com/s/QogENxhotboct9wn7GgYUw)我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。
|
||||
除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解[42. 接雨水](https://programmercarl.com/0042.接雨水.html)我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。
|
||||
|
||||
剩下就是分析清楚如下三种情况:
|
||||
|
||||
@ -195,40 +195,6 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
动态规划
|
||||
```java
|
||||
class Solution {
|
||||
public int largestRectangleArea(int[] heights) {
|
||||
int length = heights.length;
|
||||
int[] minLeftIndex = new int [length];
|
||||
int[] maxRigthIndex = new int [length];
|
||||
|
||||
// 记录左边第一个小于该柱子的下标
|
||||
minLeftIndex[0] = -1 ;
|
||||
for (int i = 1; i < length; i++) {
|
||||
int t = i - 1;
|
||||
// 这里不是用if,而是不断向右寻找的过程
|
||||
while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];
|
||||
minLeftIndex[i] = t;
|
||||
}
|
||||
// 记录每个柱子 右边第一个小于该柱子的下标
|
||||
maxRigthIndex[length - 1] = length;
|
||||
for (int i = length - 2; i >= 0; i--) {
|
||||
int t = i + 1;
|
||||
while(t < length && heights[t] >= heights[i]) t = maxRigthIndex[t];
|
||||
maxRigthIndex[i] = t;
|
||||
}
|
||||
// 求和
|
||||
int result = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int sum = heights[i] * (maxRigthIndex[i] - minLeftIndex[i] - 1);
|
||||
result = Math.max(sum, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
动态规划
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 第90题.子集II
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/subsets-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/subsets-ii/)
|
||||
|
||||
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
|
||||
|
||||
@ -30,11 +30,11 @@
|
||||
|
||||
## 思路
|
||||
|
||||
做本题之前一定要先做[78.子集](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)。
|
||||
做本题之前一定要先做[78.子集](https://programmercarl.com/0078.子集.html)。
|
||||
|
||||
这道题目和[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)区别就是集合里有重复元素了,而且求取的子集要去重。
|
||||
这道题目和[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)区别就是集合里有重复元素了,而且求取的子集要去重。
|
||||
|
||||
那么关于回溯算法中的去重问题,**在[40.组合总和II](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)中已经详细讲解过了,和本题是一个套路**。
|
||||
那么关于回溯算法中的去重问题,**在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html)中已经详细讲解过了,和本题是一个套路**。
|
||||
|
||||
**剧透一下,后期要讲解的排列问题里去重也是这个套路,所以理解“树层去重”和“树枝去重”非常重要**。
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
从图中可以看出,同一树层上重复取2 就要过滤掉,同一树枝上就可以重复取2,因为同一树枝上元素的集合才是唯一子集!
|
||||
|
||||
本题就是其实就是[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)也讲过了,所以我就直接给出代码了:
|
||||
本题就是其实就是[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)的基础上加上了去重,去重我们在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html)也讲过了,所以我就直接给出代码了:
|
||||
|
||||
## C++代码
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
## 93.复原IP地址
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/restore-ip-addresses/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/restore-ip-addresses/)
|
||||
|
||||
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
|
||||
|
||||
@ -45,11 +45,11 @@ s 仅由数字组成
|
||||
|
||||
## 思路
|
||||
|
||||
做这道题目之前,最好先把[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)这个做了。
|
||||
做这道题目之前,最好先把[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。
|
||||
|
||||
这道题目相信大家刚看的时候,应该会一脸茫然。
|
||||
|
||||
其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)就十分类似了。
|
||||
其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)就十分类似了。
|
||||
|
||||
切割问题可以抽象为树型结构,如图:
|
||||
|
||||
@ -60,7 +60,7 @@ s 仅由数字组成
|
||||
|
||||
* 递归参数
|
||||
|
||||
在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我们就提到切割问题类似组合问题。
|
||||
在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我们就提到切割问题类似组合问题。
|
||||
|
||||
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
|
||||
|
||||
@ -76,7 +76,7 @@ startIndex一定是需要的,因为不能重复分割,记录下一层递归
|
||||
|
||||
* 递归终止条件
|
||||
|
||||
终止条件和[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
|
||||
终止条件和[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
|
||||
|
||||
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
|
||||
|
||||
@ -96,7 +96,7 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
|
||||
|
||||
* 单层搜索的逻辑
|
||||
|
||||
在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中已经讲过在循环遍历中如何截取子串。
|
||||
在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中已经讲过在循环遍历中如何截取子串。
|
||||
|
||||
在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法。
|
||||
|
||||
@ -164,7 +164,7 @@ bool isValid(const string& s, int start, int end) {
|
||||
## C++代码
|
||||
|
||||
|
||||
根据[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)给出的回溯算法模板:
|
||||
根据[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)给出的回溯算法模板:
|
||||
|
||||
```
|
||||
void backtracking(参数) {
|
||||
@ -239,11 +239,11 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
在[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)中我列举的分割字符串的难点,本题都覆盖了。
|
||||
在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。
|
||||
|
||||
而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
|
||||
|
||||
可以说是[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)的加强版。
|
||||
可以说是[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)的加强版。
|
||||
|
||||
在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 96.不同的二叉搜索树
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/unique-binary-search-trees/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/unique-binary-search-trees/)
|
||||
|
||||
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
这道题目描述很简短,但估计大部分同学看完都是懵懵的状态,这得怎么统计呢?
|
||||
|
||||
关于什么是二叉搜索树,我们之前在讲解二叉树专题的时候已经详细讲解过了,也可以看看这篇[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)在回顾一波。
|
||||
关于什么是二叉搜索树,我们之前在讲解二叉树专题的时候已经详细讲解过了,也可以看看这篇[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)在回顾一波。
|
||||
|
||||
了解了二叉搜索树之后,我们应该先举几个例子,画画图,看看有没有什么规律,如图:
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 98.验证二叉搜索树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/validate-binary-search-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/validate-binary-search-tree/)
|
||||
|
||||
|
||||
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
|
||||
@ -121,7 +121,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
|
||||
|
||||
要定义一个longlong的全局变量,用来比较遍历的节点是否有序,因为后台测试数据中有int最小值,所以定义为longlong的类型,初始化为longlong最小值。
|
||||
|
||||
注意递归函数要有bool类型的返回值, 我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值。
|
||||
注意递归函数要有bool类型的返回值, 我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html) 中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值。
|
||||
|
||||
其实本题是同样的道理,我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回。
|
||||
|
||||
@ -210,7 +210,7 @@ public:
|
||||
|
||||
## 迭代法
|
||||
|
||||
可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg),[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
|
||||
可以用迭代法模拟二叉树中序遍历,对前中后序迭代法生疏的同学可以看这两篇[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html),[二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)
|
||||
|
||||
迭代法中序遍历稍加改动就可以了,代码如下:
|
||||
|
||||
@ -240,7 +240,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
在[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。
|
||||
在[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)中我们分明写出了痛哭流涕的简洁迭代法,怎么在这里不行了呢,因为本题是要验证二叉搜索树啊。
|
||||
|
||||
## 总结
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
# 100. 相同的树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/same-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/same-tree/)
|
||||
|
||||
给定两个二叉树,编写一个函数来检验它们是否相同。
|
||||
|
||||
@ -23,11 +23,11 @@
|
||||
|
||||
# 思路
|
||||
|
||||
在[101.对称二叉树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)中,我们讲到对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了**其实我们要比较的是两个树(这两个树是根节点的左右子树)**,所以在递归遍历的过程中,也是要同时遍历两棵树。
|
||||
在[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)中,我们讲到对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了**其实我们要比较的是两个树(这两个树是根节点的左右子树)**,所以在递归遍历的过程中,也是要同时遍历两棵树。
|
||||
|
||||
理解这一本质之后,就会发现,求二叉树是否对称,和求二叉树是否相同几乎是同一道题目。
|
||||
|
||||
**如果没有读过[二叉树:我对称么?](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)这一篇,请认真读完再做这道题,就会有感觉了。**
|
||||
**如果没有读过[二叉树:我对称么?](https://programmercarl.com/0101.对称二叉树.html)这一篇,请认真读完再做这道题,就会有感觉了。**
|
||||
|
||||
递归三部曲中:
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
bool compare(TreeNode* tree1, TreeNode* tree2)
|
||||
```
|
||||
|
||||
分析过程同[101.对称二叉树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)。
|
||||
分析过程同[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)。
|
||||
|
||||
2. 确定终止条件
|
||||
|
||||
@ -68,7 +68,7 @@ else if (tree1 == NULL && tree2 == NULL) return true;
|
||||
else if (tree1->val != tree2->val) return false; // 注意这里我没有使用else
|
||||
```
|
||||
|
||||
分析过程同[101.对称二叉树](https://mp.weixin.qq.com/s/Kgf0gjvlDlNDfKIH2b1Oxg)
|
||||
分析过程同[101.对称二叉树](https://programmercarl.com/0101.对称二叉树.html)
|
||||
|
||||
3. 确定单层递归的逻辑
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 101. 对称二叉树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/symmetric-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/symmetric-tree/)
|
||||
|
||||
给定一个二叉树,检查它是否是镜像对称的。
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
* 104.二叉树的最大深度
|
||||
* 111.二叉树的最小深度
|
||||
|
||||
在之前写过这篇文章 [二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/Gb3BjakIKGNpup2jYtTzog),可惜当时只打了5个,还不够,再给我一次机会,我打十个!
|
||||
在之前写过这篇文章 [二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html),可惜当时只打了5个,还不够,再给我一次机会,我打十个!
|
||||
|
||||

|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
# 102.二叉树的层序遍历
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-level-order-traversal/)
|
||||
|
||||
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
|
||||
|
||||
@ -38,9 +38,9 @@
|
||||
|
||||
我们之前讲过了三篇关于二叉树的深度优先遍历的文章:
|
||||
|
||||
* [二叉树:前中后序递归法](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)
|
||||
* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)
|
||||
* [二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)
|
||||
* [二叉树:前中后序递归法](https://programmercarl.com/二叉树的递归遍历.html)
|
||||
* [二叉树:前中后序迭代法](https://programmercarl.com/二叉树的迭代遍历.html)
|
||||
* [二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)
|
||||
|
||||
接下来我们再来介绍二叉树的另一种遍历方式:层序遍历。
|
||||
|
||||
@ -233,7 +233,7 @@ var levelOrder = function(root) {
|
||||
|
||||
# 107.二叉树的层次遍历 II
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/)
|
||||
|
||||
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
|
||||
|
||||
@ -410,7 +410,7 @@ var levelOrderBottom = function(root) {
|
||||
|
||||
# 199.二叉树的右视图
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/binary-tree-right-side-view/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-right-side-view/)
|
||||
|
||||
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
|
||||
|
||||
@ -587,7 +587,7 @@ var rightSideView = function(root) {
|
||||
|
||||
# 637.二叉树的层平均值
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/)
|
||||
|
||||
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
|
||||
|
||||
@ -771,7 +771,7 @@ var averageOfLevels = function(root) {
|
||||
|
||||
# 429.N叉树的层序遍历
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/)
|
||||
|
||||
给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
|
||||
|
||||
@ -991,7 +991,7 @@ var levelOrder = function(root) {
|
||||
|
||||
# 515.在每个树行中找最大值
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)
|
||||
|
||||
您需要在二叉树的每一行中找到最大的值。
|
||||
|
||||
@ -1072,32 +1072,6 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
//方法二:用一个max变量来保存最大值
|
||||
class Solution {
|
||||
public List<Integer> largestValues(TreeNode root) {
|
||||
Queue<TreeNode> queue = new LinkedList<TreeNode>();
|
||||
List<Integer> result = new ArrayList<>();
|
||||
if (root != null) queue.add(root);
|
||||
|
||||
while(!queue.isEmpty()){
|
||||
int size = queue.size();
|
||||
int max = Integer.MIN_VALUE; // 初始化为最小值
|
||||
for(int i = 0; i < size; i++){
|
||||
TreeNode node = queue.poll();
|
||||
max = Math.max(node.val, max);
|
||||
if(node.left != null)
|
||||
queue.add(node.left);
|
||||
if(node.right != null)
|
||||
queue.add(node.right);
|
||||
}
|
||||
result.add(max); // 取最大值放进数组
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
go:
|
||||
|
||||
```GO
|
||||
@ -1172,7 +1146,7 @@ var largestValues = function(root) {
|
||||
|
||||
# 116.填充每个节点的下一个右侧节点指针
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
|
||||
|
||||
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
|
||||
|
||||
@ -1340,8 +1314,7 @@ func connect(root *Node) *Node {
|
||||
|
||||
# 117.填充每个节点的下一个右侧节点指针II
|
||||
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/)
|
||||
|
||||
思路:
|
||||
|
||||
@ -1503,7 +1476,7 @@ func connect(root *Node) *Node {
|
||||
```
|
||||
# 104.二叉树的最大深度
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
|
||||
|
||||
给定一个二叉树,找出其最大深度。
|
||||
|
||||
@ -1588,7 +1561,7 @@ JavaScript:
|
||||
|
||||
# 111.二叉树的最小深度
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
|
||||
|
||||
相对于 104.二叉树的最大深度 ,本题还也可以使用层序遍历的方式来解决,思路是一样的。
|
||||
|
||||
@ -1623,43 +1596,6 @@ public:
|
||||
```
|
||||
|
||||
Java:
|
||||
```java
|
||||
class Solution {
|
||||
|
||||
public int minDepth(TreeNode root){
|
||||
if (root == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Queue<TreeNode> queue = new LinkedList<>();
|
||||
queue.offer(root);
|
||||
int depth = 0;
|
||||
|
||||
while (!queue.isEmpty()){
|
||||
|
||||
int size = queue.size();
|
||||
depth++;
|
||||
|
||||
TreeNode cur = null;
|
||||
for (int i = 0; i < size; i++) {
|
||||
cur = queue.poll();
|
||||
|
||||
//如果当前节点的左右孩子都为空,直接返回最小深度
|
||||
if (cur.left == null && cur.right == null){
|
||||
return depth;
|
||||
}
|
||||
|
||||
if (cur.left != null) queue.offer(cur.left);
|
||||
if (cur.right != null) queue.offer(cur.right);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Python 3:
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
# 104.二叉树的最大深度
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
|
||||
|
||||
给定一个二叉树,找出其最大深度。
|
||||
|
||||
@ -127,7 +127,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
};
|
||||
```
|
||||
```
|
||||
|
||||
**可以看出使用了前序(中左右)的遍历顺序,这才是真正求深度的逻辑!**
|
||||
|
||||
@ -167,7 +167,7 @@ public:
|
||||
|
||||
所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
|
||||
|
||||
如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
|
||||
如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)
|
||||
|
||||
c++代码如下:
|
||||
|
||||
@ -198,7 +198,7 @@ public:
|
||||
|
||||
# 559.n叉树的最大深度
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-n-ary-tree/)
|
||||
|
||||
给定一个 n 叉树,找到其最大深度。
|
||||
|
||||
@ -481,7 +481,7 @@ var maxdepth = function(root) {
|
||||
if (!root) return root
|
||||
return 1 + math.max(maxdepth(root.left), maxdepth(root.right))
|
||||
};
|
||||
```
|
||||
```
|
||||
|
||||
二叉树最大深度递归遍历
|
||||
```javascript
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
## 106.从中序与后序遍历序列构造二叉树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/)
|
||||
|
||||
根据一棵树的中序遍历与后序遍历构造二叉树。
|
||||
|
||||
@ -95,7 +95,7 @@ TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
|
||||
|
||||
**在切割的过程中会产生四个区间,把握不好不变量的话,一会左闭右开,一会左闭又闭,必然乱套!**
|
||||
|
||||
我在[数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)和[数组:这个循环可以转懵很多人!](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
|
||||
我在[数组:每次遇到二分法,都是一看就会,一写就废](https://programmercarl.com/0035.搜索插入位置.html)和[数组:这个循环可以转懵很多人!](https://programmercarl.com/0059.螺旋矩阵II.html)中都强调过循环不变量的重要性,在二分查找以及螺旋矩阵的求解中,坚持循环不变量非常重要,本题也是。
|
||||
|
||||
|
||||
首先要切割中序数组,为什么先切割中序数组呢?
|
||||
@ -396,7 +396,7 @@ public:
|
||||
|
||||
## 105.从前序与中序遍历序列构造二叉树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/)
|
||||
|
||||
根据一棵树的前序遍历与中序遍历构造二叉树。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 108.将有序数组转换为二叉搜索树
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/)
|
||||
|
||||
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
|
||||
|
||||
@ -25,10 +25,10 @@
|
||||
|
||||
做这道题目之前大家可以了解一下这几道:
|
||||
|
||||
* [106.从中序与后序遍历序列构造二叉树](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)
|
||||
* [654.最大二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中其实已经讲过了,如果根据数组构造一颗二叉树。
|
||||
* [701.二叉搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)
|
||||
* [450.删除二叉搜索树中的节点](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw)
|
||||
* [106.从中序与后序遍历序列构造二叉树](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)
|
||||
* [654.最大二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一颗二叉树。
|
||||
* [701.二叉搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)
|
||||
* [450.删除二叉搜索树中的节点](https://programmercarl.com/0450.删除二叉搜索树中的节点.html)
|
||||
|
||||
|
||||
进入正题:
|
||||
@ -38,11 +38,11 @@
|
||||
其实这里不用强调平衡二叉搜索树,数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取,**所以想构成不平衡的二叉树是自找麻烦**。
|
||||
|
||||
|
||||
在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)和[二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)中其实已经讲过了,如果根据数组构造一颗二叉树。
|
||||
在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)和[二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)中其实已经讲过了,如果根据数组构造一颗二叉树。
|
||||
|
||||
**本质就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间**。
|
||||
|
||||
本题其实要比[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 和 [二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)简单一些,因为有序数组构造二叉搜索树,寻找分割点就比较容易了。
|
||||
本题其实要比[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)简单一些,因为有序数组构造二叉搜索树,寻找分割点就比较容易了。
|
||||
|
||||
分割点就是数组中间位置的节点。
|
||||
|
||||
@ -68,11 +68,11 @@
|
||||
|
||||
删除二叉树节点,增加二叉树节点,都是用递归函数的返回值来完成,这样是比较方便的。
|
||||
|
||||
相信大家如果仔细看了[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)和[二叉树:搜索树中的删除操作](https://mp.weixin.qq.com/s/-p-Txvch1FFk3ygKLjPAKw),一定会对递归函数返回值的作用深有感触。
|
||||
相信大家如果仔细看了[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)和[二叉树:搜索树中的删除操作](https://programmercarl.com/0450.删除二叉搜索树中的节点.html),一定会对递归函数返回值的作用深有感触。
|
||||
|
||||
那么本题要构造二叉树,依然用递归函数的返回值来构造中节点的左右孩子。
|
||||
|
||||
再来看参数,首先是传入数组,然后就是左下表left和右下表right,我们在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg)中提过,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下表来操作原数组。
|
||||
再来看参数,首先是传入数组,然后就是左下表left和右下表right,我们在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html)中提过,在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下表来操作原数组。
|
||||
|
||||
所以代码如下:
|
||||
|
||||
@ -83,7 +83,7 @@ TreeNode* traversal(vector<int>& nums, int left, int right)
|
||||
|
||||
这里注意,**我这里定义的是左闭右闭区间,在不断分割的过程中,也会坚持左闭右闭的区间,这又涉及到我们讲过的循环不变量**。
|
||||
|
||||
在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg),[35.搜索插入位置](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q) 和[59.螺旋矩阵II](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)都详细讲过循环不变量。
|
||||
在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html),[35.搜索插入位置](https://programmercarl.com/0035.搜索插入位置.html) 和[59.螺旋矩阵II](https://programmercarl.com/0059.螺旋矩阵II.html)都详细讲过循环不变量。
|
||||
|
||||
|
||||
* 确定递归终止条件
|
||||
@ -98,7 +98,7 @@ if (left > right) return nullptr;
|
||||
|
||||
* 确定单层递归的逻辑
|
||||
|
||||
首先取数组中间元素的位置,不难写出`int mid = (left + right) / 2;`,**这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在[二分法](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)中尤其需要注意!**
|
||||
首先取数组中间元素的位置,不难写出`int mid = (left + right) / 2;`,**这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在[二分法](https://programmercarl.com/0035.搜索插入位置.html)中尤其需要注意!**
|
||||
|
||||
所以可以这么写:`int mid = left + ((right - left) / 2);`
|
||||
|
||||
@ -194,7 +194,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
**在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/7r66ap2s-shvVvlZxo59xg) 和 [二叉树:构造一棵最大的二叉树](https://mp.weixin.qq.com/s/1iWJV6Aov23A7xCF4nV88w)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。
|
||||
**在[二叉树:构造二叉树登场!](https://programmercarl.com/0106.从中序与后序遍历序列构造二叉树.html) 和 [二叉树:构造一棵最大的二叉树](https://programmercarl.com/0654.最大二叉树.html)之后,我们顺理成章的应该构造一下二叉搜索树了,一不小心还是一棵平衡二叉搜索树**。
|
||||
|
||||
其实思路也是一样的,不断中间分割,然后递归处理左区间,右区间,也可以说是分治。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 110.平衡二叉树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/balanced-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/balanced-binary-tree/)
|
||||
|
||||
给定一个二叉树,判断它是否是高度平衡的二叉树。
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
# 题外话
|
||||
|
||||
|
||||
咋眼一看这道题目和[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)很像,其实有很大区别。
|
||||
咋眼一看这道题目和[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)很像,其实有很大区别。
|
||||
|
||||
这里强调一波概念:
|
||||
|
||||
@ -51,11 +51,11 @@
|
||||
|
||||
因为求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
|
||||
|
||||
有的同学一定疑惑,为什么[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中求的是二叉树的最大深度,也用的是后序遍历。
|
||||
有的同学一定疑惑,为什么[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中求的是二叉树的最大深度,也用的是后序遍历。
|
||||
|
||||
**那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这颗树的最大深度,所以才可以使用后序遍历。**
|
||||
|
||||
在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
|
||||
在[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中,如果真正求取二叉树的最大深度,代码应该写成如下:(前序遍历)
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
@ -228,7 +228,7 @@ public:
|
||||
|
||||
## 迭代
|
||||
|
||||
在[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
|
||||
在[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。
|
||||
|
||||
本题的迭代方式可以先定义一个函数,专门用来求高度。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 111.二叉树的最小深度
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
|
||||
|
||||
给定一个二叉树,找出其最小深度。
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
# 思路
|
||||
|
||||
看完了这篇[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw),再来看看如何求最小深度。
|
||||
看完了这篇[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),再来看看如何求最小深度。
|
||||
|
||||
直觉上好像和求最大深度差不多,其实还是差不少的。
|
||||
|
||||
@ -154,9 +154,9 @@ public:
|
||||
|
||||
## 迭代法
|
||||
|
||||
相对于[104.二叉树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw),本题还可以使用层序遍历的方式来解决,思路是一样的。
|
||||
相对于[104.二叉树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html),本题还可以使用层序遍历的方式来解决,思路是一样的。
|
||||
|
||||
如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
|
||||
如果对层序遍历还不清楚的话,可以看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)
|
||||
|
||||
**需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点**
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
# 112. 路径总和
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/path-sum/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/path-sum/)
|
||||
|
||||
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
再来看返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
|
||||
|
||||
* 如果需要搜索整颗二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
|
||||
* 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)中介绍)
|
||||
* 如果需要搜索整颗二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在[236. 二叉树的最近公共祖先](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中介绍)
|
||||
* 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
|
||||
|
||||
而本题我们要找一条符合条件的路径,所以递归函数需要返回值,及时返回,那么返回类型是什么呢?
|
||||
@ -218,7 +218,7 @@ public:
|
||||
|
||||
# 113. 路径总和ii
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/path-sum-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/path-sum-ii/)
|
||||
|
||||
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 115.不同的子序列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/distinct-subsequences/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/distinct-subsequences/)
|
||||
|
||||
给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。
|
||||
|
||||
@ -29,7 +29,7 @@ s 和 t 由英文字母组成
|
||||
|
||||
这道题目相对于72. 编辑距离,简单了不少,因为本题相当于只有删除操作,不用考虑替换增加之类的。
|
||||
|
||||
但相对于刚讲过的[动态规划:392.判断子序列](https://mp.weixin.qq.com/s/2pjT4B4fjfOx5iB6N6xyng)就有难度了,这道题目双指针法可就做不了了,来看看动规五部曲分析如下:
|
||||
但相对于刚讲过的[动态规划:392.判断子序列](https://programmercarl.com/0392.判断子序列.html)就有难度了,这道题目双指针法可就做不了了,来看看动规五部曲分析如下:
|
||||
|
||||
1. 确定dp数组(dp table)以及下标的含义
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 116. 填充每个节点的下一个右侧节点指针
|
||||
|
||||
链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
|
||||
|
||||
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
|
||||
|
||||
@ -87,7 +87,7 @@ public:
|
||||
|
||||
## 迭代(层序遍历)
|
||||
|
||||
本题使用层序遍历是最为直观的,如果对层序遍历不了解,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)。
|
||||
本题使用层序遍历是最为直观的,如果对层序遍历不了解,看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)。
|
||||
|
||||
层序遍历本来就是一层一层的去遍历,记录一层的头结点(nodePre),然后让nodePre指向当前遍历的节点就可以了。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 121. 买卖股票的最佳时机
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)
|
||||
|
||||
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 122.买卖股票的最佳时机II
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)
|
||||
|
||||
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 122.买卖股票的最佳时机II
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)
|
||||
|
||||
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
|
||||
|
||||
@ -38,12 +38,12 @@
|
||||
|
||||
## 思路
|
||||
|
||||
本题我们在讲解贪心专题的时候就已经讲解过了[贪心算法:买卖股票的最佳时机II](https://mp.weixin.qq.com/s/VsTFA6U96l18Wntjcg3fcg),只不过没有深入讲解动态规划的解法,那么这次我们再好好分析一下动规的解法。
|
||||
本题我们在讲解贪心专题的时候就已经讲解过了[贪心算法:买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html),只不过没有深入讲解动态规划的解法,那么这次我们再好好分析一下动规的解法。
|
||||
|
||||
|
||||
本题和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)的唯一区别本题股票可以买卖多次了(注意只有一只股票,所以再次购买前要出售掉之前的股票)
|
||||
本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的唯一区别本题股票可以买卖多次了(注意只有一只股票,所以再次购买前要出售掉之前的股票)
|
||||
|
||||
**在动规五部曲中,这个区别主要是体现在递推公式上,其他都和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)一样一样的**。
|
||||
**在动规五部曲中,这个区别主要是体现在递推公式上,其他都和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)一样一样的**。
|
||||
|
||||
所以我们重点讲一讲递推公式。
|
||||
|
||||
@ -57,10 +57,9 @@
|
||||
* 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
|
||||
* 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i]
|
||||
|
||||
**注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况**。
|
||||
|
||||
**注意这里和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)唯一不同的地方,就是推导dp[i][0]的时候,第i天买入股票的情况**。
|
||||
|
||||
在[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。
|
||||
在[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。
|
||||
|
||||
而本题,因为一只股票可以买卖多次,所以当第i天买入股票的时候,所持有的现金可能有之前买卖过的利润。
|
||||
|
||||
@ -70,7 +69,7 @@
|
||||
* 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
|
||||
* 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0]
|
||||
|
||||
**注意这里和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)就是一样的逻辑,卖出股票收获利润(可能是负值)天经地义!**
|
||||
**注意这里和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)就是一样的逻辑,卖出股票收获利润(可能是负值)天经地义!**
|
||||
|
||||
代码如下:(注意代码中的注释,标记了和121.买卖股票的最佳时机唯一不同的地方)
|
||||
|
||||
@ -94,7 +93,7 @@ public:
|
||||
* 时间复杂度:O(n)
|
||||
* 空间复杂度:O(n)
|
||||
|
||||
大家可以本题和[121. 买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ)的代码几乎一样,唯一的区别在:
|
||||
大家可以本题和[121. 买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html)的代码几乎一样,唯一的区别在:
|
||||
|
||||
```
|
||||
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
|
||||
@ -122,7 +121,7 @@ public:
|
||||
return dp[(len - 1) % 2][1];
|
||||
}
|
||||
};
|
||||
```
|
||||
```
|
||||
|
||||
* 时间复杂度:O(n)
|
||||
* 空间复杂度:O(1)
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 123.买卖股票的最佳时机III
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/)
|
||||
|
||||
|
||||
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
|
||||
@ -44,7 +44,7 @@
|
||||
## 思路
|
||||
|
||||
|
||||
这道题目相对 [121.买卖股票的最佳时机](https://mp.weixin.qq.com/s/keWo5qYJY4zmHn3amfXdfQ) 和 [122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) 难了不少。
|
||||
这道题目相对 [121.买卖股票的最佳时机](https://programmercarl.com/0121.买卖股票的最佳时机.html) 和 [122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II.html) 难了不少。
|
||||
|
||||
关键在于至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖。
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
## 链接
|
||||
https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/)
|
||||
|
||||
## 思路
|
||||
|
||||
本题和[113.路径总和II](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 和 [112.路径总和](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg) 做了。
|
||||
本题和[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii)是类似的思路,做完这道题,可以顺便把[113.路径总和II](https://programmercarl.com/0112.路径总和.html#_113-路径总和ii) 和 [112.路径总和](https://programmercarl.com/0112.路径总和.html#_112-路径总和) 做了。
|
||||
|
||||
结合112.路径总和 和 113.路径总和II,我在讲了[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg),如果大家对二叉树递归函数什么时候需要返回值很迷茫,可以看一下。
|
||||
结合112.路径总和 和 113.路径总和II,我在讲了[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html),如果大家对二叉树递归函数什么时候需要返回值很迷茫,可以看一下。
|
||||
|
||||
接下来在看本题,就简单多了,本题其实需要使用回溯,但一些同学可能都不知道自己用了回溯,在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)中,我详细讲解了二叉树的递归中,如何使用了回溯。
|
||||
接下来在看本题,就简单多了,本题其实需要使用回溯,但一些同学可能都不知道自己用了回溯,在[二叉树:以为使用了递归,其实还隐藏着回溯](https://programmercarl.com/二叉树中递归带着回溯.html)中,我详细讲解了二叉树的递归中,如何使用了回溯。
|
||||
|
||||
接下来我们来看题:
|
||||
|
||||
@ -17,11 +17,11 @@ https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/
|
||||
|
||||
### 递归三部曲
|
||||
|
||||
如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://mp.weixin.qq.com/s/PwVIfxDlT3kRgMASWAMGhA)
|
||||
如果对递归三部曲不了解的话,可以看这里:[二叉树:前中后递归详解](https://programmercarl.com/二叉树的递归遍历.html)
|
||||
|
||||
* 确定递归函数返回值及其参数
|
||||
|
||||
这里我们要遍历整个二叉树,且需要要返回值做逻辑处理,所有返回值为void,在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中,详细讲解了返回值问题。
|
||||
这里我们要遍历整个二叉树,且需要要返回值做逻辑处理,所有返回值为void,在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中,详细讲解了返回值问题。
|
||||
|
||||
参数只需要把根节点传入,此时还需要定义两个全局遍历,一个是result,记录最终结果,一个是vector<int> path。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 131.分割回文串
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/palindrome-partitioning/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning/)
|
||||
|
||||
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
|
||||
本题递归函数参数还需要startIndex,因为切割过的地方,不能重复切割,和组合问题也是保持一致的。
|
||||
|
||||
在[回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)中我们深入探讨了组合问题什么时候需要startIndex,什么时候不需要startIndex。
|
||||
在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)中我们深入探讨了组合问题什么时候需要startIndex,什么时候不需要startIndex。
|
||||
|
||||
代码如下:
|
||||
|
||||
@ -143,7 +143,7 @@ for (int i = startIndex; i < s.size(); i++) {
|
||||
}
|
||||
```
|
||||
|
||||
如果大家对双指针法有生疏了,传送门:[双指针法:总结篇!](https://mp.weixin.qq.com/s/_p7grwjISfMh0U65uOyCjA)
|
||||
如果大家对双指针法有生疏了,传送门:[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)
|
||||
|
||||
此时关键代码已经讲解完毕,整体代码如下(详细注释了)
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
# 132. 分割回文串 II
|
||||
|
||||
链接:https://leetcode-cn.com/problems/palindrome-partitioning-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
|
||||
|
||||
给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
示例 3:
|
||||
输入:s = "ab"
|
||||
输出:1
|
||||
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
# 思路
|
||||
|
||||
我们在讲解回溯法系列的时候,讲过了这道题目[回溯算法:131.分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)。
|
||||
我们在讲解回溯法系列的时候,讲过了这道题目[回溯算法:131.分割回文串](https://programmercarl.com/0131.分割回文串.html)。
|
||||
|
||||
本题呢其实也可以使用回溯法,只不过会超时!(通过记忆化回溯,也可以过,感兴趣的同学可以自行研究一下)
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
关于回文子串,两道题目题目大家是一定要掌握的。
|
||||
|
||||
* [动态规划:647. 回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw)
|
||||
* [动态规划:647. 回文子串](https://programmercarl.com/0647.回文子串.html)
|
||||
* 5.最长回文子串 和 647.回文子串基本一样的
|
||||
|
||||
这两道题目是回文子串的基础题目,本题也要用到相关的知识点。
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 134. 加油站
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/gas-station/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/gas-station/)
|
||||
|
||||
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 135. 分发糖果
|
||||
|
||||
链接:https://leetcode-cn.com/problems/candy/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/candy/)
|
||||
|
||||
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
## 139.单词拆分
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/word-break/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/word-break/)
|
||||
|
||||
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
|
||||
|
||||
@ -37,9 +37,9 @@
|
||||
|
||||
## 思路
|
||||
|
||||
看到这道题目的时候,大家应该回想起我们之前讲解回溯法专题的时候,讲过的一道题目[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q),就是枚举字符串的所有分割情况。
|
||||
看到这道题目的时候,大家应该回想起我们之前讲解回溯法专题的时候,讲过的一道题目[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html),就是枚举字符串的所有分割情况。
|
||||
|
||||
[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q):是枚举分割后的所有子串,判断是否回文。
|
||||
[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html):是枚举分割后的所有子串,判断是否回文。
|
||||
|
||||
本道是枚举分割所有字符串,判断是否在字典里出现过。
|
||||
|
||||
@ -161,11 +161,11 @@ dp[0]表示如果字符串为空的话,说明出现在字典里。
|
||||
|
||||
**如果求排列数就是外层for遍历背包,内层for循环遍历物品**。
|
||||
|
||||
对这个结论还有疑问的同学可以看这篇[本周小结!(动态规划系列五)](https://mp.weixin.qq.com/s/znj-9j8mWymRFaPjJN2Qnw),这篇本周小节中,我做了如下总结:
|
||||
对这个结论还有疑问的同学可以看这篇[本周小结!(动态规划系列五)](https://programmercarl.com/%E5%91%A8%E6%80%BB%E7%BB%93/20210204动规周末总结.html),这篇本周小节中,我做了如下总结:
|
||||
|
||||
求组合数:[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)
|
||||
求排列数:[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://mp.weixin.qq.com/s/e_wacnELo-2PG76EjrUakA)
|
||||
求最小数:[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)、[动态规划:279.完全平方数](https://mp.weixin.qq.com/s/VfJT78p7UGpDZsapKF_QJQ)
|
||||
求组合数:[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)
|
||||
求排列数:[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和.html)、[动态规划:70. 爬楼梯进阶版(完全背包)](https://programmercarl.com/0070.爬楼梯完全背包版本.html)
|
||||
求最小数:[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)、[动态规划:279.完全平方数](https://programmercarl.com/0279.完全平方数.html)
|
||||
|
||||
本题最终要求的是是否都出现过,所以对出现单词集合里的元素是组合还是排列,并不在意!
|
||||
|
||||
@ -215,7 +215,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
本题和我们之前讲解回溯专题的[回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)非常像,所以我也给出了对应的回溯解法。
|
||||
本题和我们之前讲解回溯专题的[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)非常像,所以我也给出了对应的回溯解法。
|
||||
|
||||
稍加分析,便可知道本题是完全背包,而且是求能否组成背包,所以遍历顺序理论上来讲 两层for循环谁先谁后都可以!
|
||||
|
||||
|
@ -66,7 +66,7 @@ public:
|
||||
|
||||
做完这道题目,可以在做做142.环形链表II,不仅仅要找环,还要找环的入口。
|
||||
|
||||
142.环形链表II题解:[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/gt_VH3hQTqNxyWcl1ECSbQ)
|
||||
142.环形链表II题解:[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)
|
||||
|
||||
|
||||
# 其他语言版本
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
## 142.环形链表II
|
||||
|
||||
https://leetcode-cn.com/problems/linked-list-cycle-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/linked-list-cycle-ii/)
|
||||
|
||||
题意:
|
||||
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
|
||||
@ -146,7 +146,7 @@ public:
|
||||
|
||||
在推理过程中,大家可能有一个疑问就是:**为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y 呢?**
|
||||
|
||||
即文章[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)中如下的地方:
|
||||
即文章[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中如下的地方:
|
||||
|
||||

|
||||
|
||||
@ -175,7 +175,7 @@ public:
|
||||
|
||||
那有同学又说了,为什么fast不能跳过去呢? 在刚刚已经说过一次了,**fast相对于slow是一次移动一个节点,所以不可能跳过去**。
|
||||
|
||||
好了,这次把为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y ,用数学推理了一下,算是对[链表:环找到了,那入口呢?](https://mp.weixin.qq.com/s/_QVP3IkRZWx9zIpQRgajzA)的补充。
|
||||
好了,这次把为什么第一次在环中相遇,slow的 步数 是 x+y 而不是 x + 若干环的长度 + y ,用数学推理了一下,算是对[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)的补充。
|
||||
|
||||
## 总结
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
# 150. 逆波兰表达式求值
|
||||
|
||||
https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/)
|
||||
|
||||
根据 逆波兰表示法,求表达式的值。
|
||||
|
||||
@ -23,7 +23,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
|
||||
|
||||
整数除法只保留整数部分。
|
||||
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
* 输入: ["2", "1", "+", "3", " * "]
|
||||
@ -40,13 +40,13 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
|
||||
* 输出: 22
|
||||
* 解释:该算式转化为常见的中缀算术表达式为:
|
||||
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
|
||||
= ((10 * (6 / (12 * -11))) + 17) + 5
|
||||
= ((10 * (6 / -132)) + 17) + 5
|
||||
= ((10 * 0) + 17) + 5
|
||||
= (0 + 17) + 5
|
||||
= 17 + 5
|
||||
= 22
|
||||
|
||||
= ((10 * (6 / (12 * -11))) + 17) + 5
|
||||
= ((10 * (6 / -132)) + 17) + 5
|
||||
= ((10 * 0) + 17) + 5
|
||||
= (0 + 17) + 5
|
||||
= 17 + 5
|
||||
= 22
|
||||
|
||||
|
||||
逆波兰表达式:是一种后缀表达式,所谓后缀就是指算符写在后面。
|
||||
|
||||
@ -62,7 +62,7 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
|
||||
|
||||
# 思路
|
||||
|
||||
在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)提到了 递归就是用栈来实现的。
|
||||
在上一篇文章中[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)提到了 递归就是用栈来实现的。
|
||||
|
||||
所以**栈与递归之间在某种程度上是可以转换的!** 这一点我们在后续讲解二叉树的时候,会更详细的讲解到。
|
||||
|
||||
@ -70,12 +70,12 @@ https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/
|
||||
|
||||
但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后续遍历的方式把二叉树序列化了,就可以了。
|
||||
|
||||
在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)中的对对碰游戏是不是就非常像了。**
|
||||
在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么**这岂不就是一个相邻字符串消除的过程,和[1047.删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)中的对对碰游戏是不是就非常像了。**
|
||||
|
||||
如动画所示:
|
||||

|
||||
|
||||
相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://mp.weixin.qq.com/s/1-x6r1wGA9mqIHW5LrMvBg)是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
|
||||
相信看完动画大家应该知道,这和[1047. 删除字符串中的所有相邻重复项](https://programmercarl.com/1047.删除字符串中的所有相邻重复项.html)是差不错的,只不过本题不要相邻元素做消除了,而是做运算!
|
||||
|
||||
C++代码如下:
|
||||
|
||||
@ -223,19 +223,17 @@ var evalRPN = function(tokens) {
|
||||
python3
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def evalRPN(self, tokens: List[str]) -> int:
|
||||
stack = []
|
||||
for item in tokens:
|
||||
if item not in {"+", "-", "*", "/"}:
|
||||
stack.append(item)
|
||||
else:
|
||||
first_num, second_num = stack.pop(), stack.pop()
|
||||
stack.append(
|
||||
int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面
|
||||
)
|
||||
return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的
|
||||
|
||||
def evalRPN(tokens) -> int:
|
||||
stack = list()
|
||||
for i in range(len(tokens)):
|
||||
if tokens[i] not in ["+", "-", "*", "/"]:
|
||||
stack.append(tokens[i])
|
||||
else:
|
||||
tmp1 = stack.pop()
|
||||
tmp2 = stack.pop()
|
||||
res = eval(tmp2+tokens[i]+tmp1)
|
||||
stack.append(str(int(res)))
|
||||
return stack[-1]
|
||||
```
|
||||
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
# 151.翻转字符串里的单词
|
||||
|
||||
https://leetcode-cn.com/problems/reverse-words-in-a-string/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/reverse-words-in-a-string/)
|
||||
|
||||
给定一个字符串,逐个翻转字符串中的每个单词。
|
||||
|
||||
@ -83,13 +83,13 @@ void removeExtraSpaces(string& s) {
|
||||
|
||||
如果不仔细琢磨一下erase的时间复杂读,还以为以上的代码是O(n)的时间复杂度呢。
|
||||
|
||||
想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww),最优的算法来移除元素也要O(n)。
|
||||
想一下真正的时间复杂度是多少,一个erase本来就是O(n)的操作,erase实现原理题目:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html),最优的算法来移除元素也要O(n)。
|
||||
|
||||
erase操作上面还套了一个for循环,那么以上代码移除冗余空格的代码时间复杂度为O(n^2)。
|
||||
|
||||
那么使用双指针法来去移除空格,最后resize(重新设置)一下字符串的大小,就可以做到O(n)的时间复杂度。
|
||||
|
||||
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)是如何移除元素的。
|
||||
如果对这个操作比较生疏了,可以再看一下这篇文章:[数组:就移除个元素很难么?](https://programmercarl.com/0027.移除元素.html)是如何移除元素的。
|
||||
|
||||
那么使用双指针来移除冗余空格代码如下: fastIndex走的快,slowIndex走的慢,最后slowIndex就标记着移除多余空格后新字符串的长度。
|
||||
|
||||
@ -125,7 +125,7 @@ void removeExtraSpaces(string& s) {
|
||||
|
||||
此时我们已经实现了removeExtraSpaces函数来移除冗余空格。
|
||||
|
||||
还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://mp.weixin.qq.com/s/_rNm66OJVl92gBDIbGpA3w)和[541.反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)里已经讲过了。
|
||||
还做实现反转字符串的功能,支持反转字符串子区间,这个实现我们分别在[344.反转字符串](https://programmercarl.com/0344.反转字符串.html)和[541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)里已经讲过了。
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
|
||||
同:[链表:链表相交](./面试题02.07.链表相交.md)
|
||||
同:[链表:链表相交](https://programmercarl.com/面试题02.07.链表相交.html)
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 188.买卖股票的最佳时机IV
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/)
|
||||
|
||||
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
|
||||
|
||||
@ -35,13 +35,13 @@
|
||||
|
||||
## 思路
|
||||
|
||||
这道题目可以说是[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)的进阶版,这里要求至多有k次交易。
|
||||
这道题目可以说是[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)的进阶版,这里要求至多有k次交易。
|
||||
|
||||
动规五部曲,分析如下:
|
||||
|
||||
1. 确定dp数组以及下标的含义
|
||||
|
||||
在[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)中,我是定义了一个二维dp数组,本题其实依然可以用一个二维dp数组。
|
||||
在[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)中,我是定义了一个二维dp数组,本题其实依然可以用一个二维dp数组。
|
||||
|
||||
使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]
|
||||
|
||||
@ -91,7 +91,7 @@ for (int j = 0; j < 2 * k - 1; j += 2) {
|
||||
}
|
||||
```
|
||||
|
||||
**本题和[动态规划:123.买卖股票的最佳时机III](https://mp.weixin.qq.com/s/Sbs157mlVDtAR0gbLpdKzg)最大的区别就是这里要类比j为奇数是买,偶数是卖剩的状态**。
|
||||
**本题和[动态规划:123.买卖股票的最佳时机III](https://programmercarl.com/0123.买卖股票的最佳时机III.html)最大的区别就是这里要类比j为奇数是买,偶数是卖剩的状态**。
|
||||
|
||||
3. dp数组如何初始化
|
||||
|
||||
|
@ -37,17 +37,17 @@
|
||||
|
||||
这道题目在字符串里其实很常见,我把字符串反转相关的题目列一下:
|
||||
|
||||
* [字符串:力扣541.反转字符串II](https://mp.weixin.qq.com/s/pzXt6PQ029y7bJ9YZB2mVQ)
|
||||
* [字符串:力扣151.翻转字符串里的单词](https://mp.weixin.qq.com/s/4j6vPFHkFAXnQhmSkq2X9g)
|
||||
* [字符串:剑指Offer58-II.左旋转字符串](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)
|
||||
* [字符串:力扣541.反转字符串II](https://programmercarl.com/0541.反转字符串II.html)
|
||||
* [字符串:力扣151.翻转字符串里的单词](https://programmercarl.com/0151.翻转字符串里的单词.html)
|
||||
* [字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)
|
||||
|
||||
本题其实和[字符串:剑指Offer58-II.左旋转字符串](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)就非常像了,剑指offer上左旋转,本题是右旋转。
|
||||
本题其实和[字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)就非常像了,剑指offer上左旋转,本题是右旋转。
|
||||
|
||||
注意题目要求是**要求使用空间复杂度为 O(1) 的 原地 算法**
|
||||
|
||||
那么我来提供一种旋转的方式哈。
|
||||
|
||||
在[字符串:剑指Offer58-II.左旋转字符串](https://mp.weixin.qq.com/s/Px_L-RfT2b_jXKcNmccPsw)中,我们提到,如下步骤就可以坐旋转字符串:
|
||||
在[字符串:剑指Offer58-II.左旋转字符串](https://programmercarl.com/剑指Offer58-II.左旋转字符串.html)中,我们提到,如下步骤就可以坐旋转字符串:
|
||||
|
||||
1. 反转区间为前n的子串
|
||||
2. 反转区间为n到末尾的子串
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 198.打家劫舍
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/house-robber/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/house-robber/)
|
||||
|
||||
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
# 第202题. 快乐数
|
||||
|
||||
https://leetcode-cn.com/problems/happy-number/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/happy-number/)
|
||||
|
||||
编写一个算法来判断一个数 n 是不是快乐数。
|
||||
|
||||
@ -36,7 +36,7 @@ https://leetcode-cn.com/problems/happy-number/
|
||||
|
||||
题目中说了会 **无限循环**,那么也就是说**求和的过程中,sum会重复出现,这对解题很重要!**
|
||||
|
||||
正如:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中所说,**当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。**
|
||||
正如:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中所说,**当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。**
|
||||
|
||||
所以这道题目使用哈希法,来判断这个sum是否重复出现,如果重复了就是return false, 否则一直找到sum为1为止。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 203.移除链表元素
|
||||
|
||||
https://leetcode-cn.com/problems/remove-linked-list-elements/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/remove-linked-list-elements/)
|
||||
|
||||
题意:删除链表中等于给定值 val 的所有节点。
|
||||
|
||||
@ -245,15 +245,13 @@ Python:
|
||||
# def __init__(self, val=0, next=None):
|
||||
# self.val = val
|
||||
# self.next = next
|
||||
|
||||
class Solution:
|
||||
def removeElements(self, head: ListNode, val: int) -> ListNode:
|
||||
dummy_head = ListNode(next=head)
|
||||
dummy_head = ListNode(next=head) #添加一个虚拟节点
|
||||
cur = dummy_head
|
||||
|
||||
while cur.next:
|
||||
if cur.next.val == val:
|
||||
cur.next = cur.next.next # 删除下一个节点
|
||||
while(cur.next!=None):
|
||||
if(cur.next.val == val):
|
||||
cur.next = cur.next.next #删除cur.next节点
|
||||
else:
|
||||
cur = cur.next
|
||||
return dummy_head.next
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 205. 同构字符串
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/isomorphic-strings/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/isomorphic-strings/)
|
||||
|
||||
给定两个字符串 s 和 t,判断它们是否是同构的。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 206.反转链表
|
||||
|
||||
https://leetcode-cn.com/problems/reverse-linked-list/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/reverse-linked-list/)
|
||||
|
||||
题意:反转一个单链表。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 209.长度最小的子数组
|
||||
|
||||
题目链接: https://leetcode-cn.com/problems/minimum-size-subarray-sum/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/minimum-size-subarray-sum/)
|
||||
|
||||
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 213.打家劫舍II
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/house-robber-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/house-robber-ii/)
|
||||
|
||||
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
|
||||
|
||||
@ -28,14 +28,14 @@
|
||||
示例 3:
|
||||
输入:nums = [0]
|
||||
输出:0
|
||||
|
||||
|
||||
提示:
|
||||
* 1 <= nums.length <= 100
|
||||
* 0 <= nums[i] <= 1000
|
||||
|
||||
## 思路
|
||||
|
||||
这道题目和[198.打家劫舍](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw)是差不多的,唯一区别就是成环了。
|
||||
这道题目和[198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html)是差不多的,唯一区别就是成环了。
|
||||
|
||||
对于一个数组,成环的话主要有如下三种情况:
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
|
||||
**而情况二 和 情况三 都包含了情况一了,所以只考虑情况二和情况三就可以了**。
|
||||
|
||||
分析到这里,本题其实比较简单了。 剩下的和[198.打家劫舍](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw)就是一样的了。
|
||||
分析到这里,本题其实比较简单了。 剩下的和[198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html)就是一样的了。
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
# 216.组合总和III
|
||||
|
||||
链接:https://leetcode-cn.com/problems/combination-sum-iii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/combination-sum-iii/)
|
||||
|
||||
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
|
||||
|
||||
@ -34,9 +34,9 @@
|
||||
|
||||
本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。
|
||||
|
||||
相对于[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。
|
||||
相对于[77. 组合](https://programmercarl.com/0077.组合.html),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。
|
||||
|
||||
想到这一点了,做过[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)之后,本题是简单一些了。
|
||||
想到这一点了,做过[77. 组合](https://programmercarl.com/0077.组合.html)之后,本题是简单一些了。
|
||||
|
||||
本题k相当于了树的深度,9(因为整个集合就是9个数)就是树的宽度。
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
|
||||
* **确定递归函数参数**
|
||||
|
||||
和[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。
|
||||
和[77. 组合](https://programmercarl.com/0077.组合.html)一样,依然需要一维数组path来存放符合条件的结果,二维数组result来存放结果集。
|
||||
|
||||
这里我依然定义path 和 result为全局变量。
|
||||
|
||||
@ -103,7 +103,7 @@ if (path.size() == k) {
|
||||
|
||||
* **单层搜索过程**
|
||||
|
||||
本题和[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)区别之一就是集合固定的就是9个数[1,...,9],所以for循环固定i<=9
|
||||
本题和[77. 组合](https://programmercarl.com/0077.组合.html)区别之一就是集合固定的就是9个数[1,...,9],所以for循环固定i<=9
|
||||
|
||||
如图:
|
||||

|
||||
@ -124,7 +124,7 @@ for (int i = startIndex; i <= 9; i++) {
|
||||
|
||||
**别忘了处理过程 和 回溯过程是一一对应的,处理有加,回溯就要有减!**
|
||||
|
||||
参照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的模板,不难写出如下C++代码:
|
||||
参照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的模板,不难写出如下C++代码:
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
@ -176,7 +176,7 @@ if (sum > targetSum) { // 剪枝操作
|
||||
}
|
||||
```
|
||||
|
||||
和[回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA) 一样,for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。
|
||||
和[回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html) 一样,for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。
|
||||
|
||||
最后C++代码如下:
|
||||
|
||||
@ -214,7 +214,7 @@ public:
|
||||
|
||||
# 总结
|
||||
|
||||
开篇就介绍了本题与[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)的区别,相对来说加了元素总和的限制,如果做完[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)再做本题在合适不过。
|
||||
开篇就介绍了本题与[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)的区别,相对来说加了元素总和的限制,如果做完[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)再做本题在合适不过。
|
||||
|
||||
分析完区别,依然把问题抽象为树形结构,按照回溯三部曲进行讲解,最后给出剪枝的优化。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 222.完全二叉树的节点个数
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/count-complete-tree-nodes/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/count-complete-tree-nodes/)
|
||||
|
||||
给出一个完全二叉树,求出该树的节点个数。
|
||||
|
||||
@ -41,13 +41,13 @@
|
||||
|
||||
首先按照普通二叉树的逻辑来求。
|
||||
|
||||
这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
|
||||
这道题目的递归法和求二叉树的深度写法类似, 而迭代法,[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)遍历模板稍稍修改一下,记录遍历的节点数量就可以了。
|
||||
|
||||
递归遍历的顺序依然是后序(左右中)。
|
||||
|
||||
### 递归
|
||||
|
||||
如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://mp.weixin.qq.com/s/jRaRcRerhEHepQbt-aKstw)。
|
||||
如果对求二叉树深度还不熟悉的话,看这篇:[二叉树:看看这些树的最大深度](https://programmercarl.com/0104.二叉树的最大深度.html)。
|
||||
|
||||
1. 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
|
||||
|
||||
@ -115,7 +115,7 @@ public:
|
||||
|
||||
### 迭代法
|
||||
|
||||
如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)。
|
||||
如果对求二叉树层序遍历还不熟悉的话,看这篇:[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)。
|
||||
|
||||
那么只要模板少做改动,加一个变量result,统计节点数量就可以了
|
||||
|
||||
@ -145,7 +145,7 @@ public:
|
||||
|
||||
## 完全二叉树
|
||||
|
||||
以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA),这篇详细介绍了各种二叉树的特性。
|
||||
以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 [关于二叉树,你该了解这些!](https://programmercarl.com/二叉树理论基础.html),这篇详细介绍了各种二叉树的特性。
|
||||
|
||||
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
# 225. 用队列实现栈
|
||||
|
||||
https://leetcode-cn.com/problems/implement-stack-using-queues/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/implement-stack-using-queues/)
|
||||
|
||||
使用队列实现栈的下列操作:
|
||||
|
||||
@ -34,7 +34,7 @@ https://leetcode-cn.com/problems/implement-stack-using-queues/
|
||||
|
||||
有的同学可能疑惑这种题目有什么实际工程意义,**其实很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!**
|
||||
|
||||
刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://mp.weixin.qq.com/s/Cj6R0qu8rFA7Et9V_ZMjCA)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行!
|
||||
刚刚做过[栈与队列:我用栈来实现队列怎么样?](https://programmercarl.com/0232.用栈实现队列.html)的同学可能依然想着用一个输入队列,一个输出队列,就可以模拟栈的功能,仔细想一下还真不行!
|
||||
|
||||
**队列模拟栈,其实一个队列就够了**,那么我们先说一说两个队列来实现栈的思路。
|
||||
|
||||
@ -294,66 +294,53 @@ Python:
|
||||
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
class MyStack:
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Python普通的Queue或SimpleQueue没有类似于peek的功能
|
||||
也无法用索引访问,在实现top的时候较为困难。
|
||||
|
||||
用list可以,但是在使用pop(0)的时候时间复杂度为O(n)
|
||||
因此这里使用双向队列,我们保证只执行popleft()和append(),因为deque可以用索引访问,可以实现和peek相似的功能
|
||||
|
||||
in - 存所有数据
|
||||
out - 仅在pop的时候会用到
|
||||
Initialize your data structure here.
|
||||
"""
|
||||
self.queue_in = deque()
|
||||
self.queue_out = deque()
|
||||
#使用两个队列来实现
|
||||
self.que1 = deque()
|
||||
self.que2 = deque()
|
||||
|
||||
def push(self, x: int) -> None:
|
||||
"""
|
||||
直接append即可
|
||||
Push element x onto stack.
|
||||
"""
|
||||
self.queue_in.append(x)
|
||||
|
||||
self.que1.append(x)
|
||||
|
||||
def pop(self) -> int:
|
||||
"""
|
||||
1. 首先确认不空
|
||||
2. 因为队列的特殊性,FIFO,所以我们只有在pop()的时候才会使用queue_out
|
||||
3. 先把queue_in中的所有元素(除了最后一个),依次出列放进queue_out
|
||||
4. 交换in和out,此时out里只有一个元素
|
||||
5. 把out中的pop出来,即是原队列的最后一个
|
||||
|
||||
tip:这不能像栈实现队列一样,因为另一个queue也是FIFO,如果执行pop()它不能像
|
||||
stack一样从另一个pop(),所以干脆in只用来存数据,pop()的时候两个进行交换
|
||||
Removes the element on top of the stack and returns that element.
|
||||
"""
|
||||
if self.empty():
|
||||
return None
|
||||
size = len(self.que1)
|
||||
size -= 1#这里先减一是为了保证最后面的元素
|
||||
while size > 0:
|
||||
size -= 1
|
||||
self.que2.append(self.que1.popleft())
|
||||
|
||||
for i in range(len(self.queue_in) - 1):
|
||||
self.queue_out.append(self.queue_in.popleft())
|
||||
|
||||
self.queue_in, self.queue_out = self.queue_out, self.queue_in # 交换in和out,这也是为啥in只用来存
|
||||
return self.queue_out.popleft()
|
||||
|
||||
result = self.que1.popleft()
|
||||
self.que1, self.que2= self.que2, self.que1#将que2和que1交换 que1经过之前的操作应该是空了
|
||||
#一定注意不能直接使用que1 = que2 这样que2的改变会影响que1 可以用浅拷贝
|
||||
return result
|
||||
|
||||
def top(self) -> int:
|
||||
"""
|
||||
1. 首先确认不空
|
||||
2. 我们仅有in会存放数据,所以返回第一个即可
|
||||
Get the top element.
|
||||
"""
|
||||
if self.empty():
|
||||
return None
|
||||
|
||||
return self.queue_in[-1]
|
||||
|
||||
return self.que1[-1]
|
||||
|
||||
def empty(self) -> bool:
|
||||
"""
|
||||
因为只有in存了数据,只要判断in是不是有数即可
|
||||
Returns whether the stack is empty.
|
||||
"""
|
||||
return len(self.queue_in) == 0
|
||||
#print(self.que1)
|
||||
if len(self.que1) == 0:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 226.翻转二叉树
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/invert-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/invert-binary-tree/)
|
||||
|
||||
翻转一棵二叉树。
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
|
||||
|
||||
|
||||
对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://mp.weixin.qq.com/s/Ww60X5mIKWdMQV4cN3ejOA)详细讲解了。
|
||||
对于二叉树的递归法的前中后序遍历,已经在[二叉树:前中后序递归遍历](https://programmercarl.com/二叉树的递归遍历.html)详细讲解了。
|
||||
|
||||
我们下文以前序遍历为例,通过动画来看一下翻转的过程:
|
||||
|
||||
@ -106,8 +106,7 @@ public:
|
||||
|
||||
### 深度优先遍历
|
||||
|
||||
|
||||
[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:
|
||||
[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:
|
||||
|
||||
C++代码迭代法(前序遍历)
|
||||
|
||||
@ -129,10 +128,10 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
如果这个代码看不懂的话可以在回顾一下[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)。
|
||||
如果这个代码看不懂的话可以在回顾一下[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)。
|
||||
|
||||
|
||||
我们在[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。
|
||||
我们在[二叉树:前中后序迭代方式的统一写法](https://programmercarl.com/二叉树的统一迭代法.html)中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。
|
||||
|
||||
C++代码如下迭代法(前序遍历)
|
||||
|
||||
@ -162,7 +161,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)。
|
||||
如果上面这个代码看不懂,回顾一下文章[二叉树:前中后序迭代方式的统一写法](https://programmercarl.com/二叉树的统一迭代法.html)。
|
||||
|
||||
### 广度优先遍历
|
||||
|
||||
@ -188,7 +187,7 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)
|
||||
如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)
|
||||
|
||||
## 拓展
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 232.用栈实现队列
|
||||
|
||||
https://leetcode-cn.com/problems/implement-queue-using-stacks/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/)
|
||||
|
||||
使用栈实现队列的下列操作:
|
||||
|
||||
@ -281,60 +281,48 @@ class MyQueue {
|
||||
|
||||
Python:
|
||||
```python
|
||||
# 使用两个栈实现先进先出的队列
|
||||
class MyQueue:
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
in主要负责push,out主要负责pop
|
||||
Initialize your data structure here.
|
||||
"""
|
||||
self.stack_in = []
|
||||
self.stack_out = []
|
||||
|
||||
self.stack1 = list()
|
||||
self.stack2 = list()
|
||||
|
||||
def push(self, x: int) -> None:
|
||||
"""
|
||||
有新元素进来,就往in里面push
|
||||
Push element x to the back of queue.
|
||||
"""
|
||||
self.stack_in.append(x)
|
||||
|
||||
# self.stack1用于接受元素
|
||||
self.stack1.append(x)
|
||||
|
||||
def pop(self) -> int:
|
||||
"""
|
||||
1. 检查如果out里面元素,则直接pop
|
||||
2. 如果out没有元素,就把in里面的元素(除了第一个)依次pop后装进out里面
|
||||
3. 直接把in剩下的元素pop出来,就是queue头部的
|
||||
Removes the element from in front of queue and returns that element.
|
||||
"""
|
||||
if self.empty:
|
||||
return None
|
||||
|
||||
if self.stack_out:
|
||||
return self.stack_out.pop()
|
||||
else:
|
||||
for i in range(1, len(self.stack_in)):
|
||||
self.stack_out.append(self.stack_in.pop())
|
||||
return self.stack_in.pop()
|
||||
|
||||
# self.stack2用于弹出元素,如果self.stack2为[],则将self.stack1中元素全部弹出给self.stack2
|
||||
if self.stack2 == []:
|
||||
while self.stack1:
|
||||
tmp = self.stack1.pop()
|
||||
self.stack2.append(tmp)
|
||||
return self.stack2.pop()
|
||||
|
||||
def peek(self) -> int:
|
||||
"""
|
||||
1. 查out有没有元素,有就把最上面的返回
|
||||
2. 如果out没有元素,就把in最下面的返回
|
||||
Get the front element.
|
||||
"""
|
||||
if self.empty:
|
||||
return None
|
||||
|
||||
if self.stack_out:
|
||||
return self.stack_out[-1]
|
||||
else:
|
||||
return self.stack_in[0]
|
||||
|
||||
if self.stack2 == []:
|
||||
while self.stack1:
|
||||
tmp = self.stack1.pop()
|
||||
self.stack2.append(tmp)
|
||||
return self.stack2[-1]
|
||||
|
||||
def empty(self) -> bool:
|
||||
"""
|
||||
只要in或者out有元素,说明队列不为空
|
||||
Returns whether the queue is empty.
|
||||
"""
|
||||
return not (self.stack_in or self.stack_out)
|
||||
|
||||
return self.stack1 == [] and self.stack2 == []
|
||||
```
|
||||
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 234.回文链表
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/palindrome-linked-list/)
|
||||
|
||||
请判断一个链表是否为回文链表。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 235. 二叉搜索树的最近公共祖先
|
||||
|
||||
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/)
|
||||
|
||||
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
做过[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)题目的同学应该知道,利用回溯从底向上搜索,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。
|
||||
做过[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)题目的同学应该知道,利用回溯从底向上搜索,遇到一个节点的左子树里有p,右子树里有q,那么当前节点就是最近公共祖先。
|
||||
|
||||
那么本题是二叉搜索树,二叉搜索树是有序的,那得好好利用一下这个特点。
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
理解这一点,本题就很好解了。
|
||||
|
||||
和[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)不同,普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。
|
||||
和[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)不同,普通二叉树求最近公共祖先需要使用回溯,从底向上来查找,二叉搜索树就不用了,因为搜索树有序(相当于自带方向),那么只要从上向下遍历就可以了。
|
||||
|
||||
那么我们可以采用前序遍历(其实这里没有中节点的处理逻辑,遍历顺序无所谓了)。
|
||||
|
||||
@ -105,7 +105,7 @@ if (cur->val > p->val && cur->val > q->val) {
|
||||
**细心的同学会发现,在这里调用递归函数的地方,把递归函数的返回值left,直接return**。
|
||||
|
||||
|
||||
在[二叉树:公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)中,如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树。
|
||||
在[二叉树:公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中,如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树。
|
||||
|
||||
搜索一条边的写法:
|
||||
|
||||
@ -192,7 +192,7 @@ public:
|
||||
|
||||
## 迭代法
|
||||
|
||||
对于二叉搜索树的迭代法,大家应该在[二叉树:二叉搜索树登场!](https://mp.weixin.qq.com/s/vsKrWRlETxCVsiRr8v_hHg)就了解了。
|
||||
对于二叉搜索树的迭代法,大家应该在[二叉树:二叉搜索树登场!](https://programmercarl.com/0700.二叉搜索树中的搜索.html)就了解了。
|
||||
|
||||
利用其有序性,迭代的方式还是比较简单的,解题思路在递归中已经分析了。
|
||||
|
||||
@ -218,7 +218,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
对于二叉搜索树的最近祖先问题,其实要比[普通二叉树公共祖先问题](https://mp.weixin.qq.com/s/n6Rk3nc_X3TSkhXHrVmBTQ)简单的多。
|
||||
对于二叉搜索树的最近祖先问题,其实要比[普通二叉树公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)简单的多。
|
||||
|
||||
不用使用回溯,二叉搜索树自带方向性,可以方便的从上向下查找目标区间,遇到目标区间内的节点,直接返回。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 236. 二叉树的最近公共祖先
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/)
|
||||
|
||||
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
|
||||
|
||||
@ -79,7 +79,7 @@ if (root == q || root == p || root == NULL) return root;
|
||||
|
||||
值得注意的是 本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,但本题我们依然要遍历树的所有节点。
|
||||
|
||||
我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)中说了 递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值!
|
||||
我们在[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)中说了 递归函数有返回值就是要遍历某一条边,但有返回值也要看如何处理返回值!
|
||||
|
||||
如果递归函数有返回值,如何区分要搜索一条边,还是搜索整个树呢?
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
# 239. 滑动窗口最大值
|
||||
|
||||
https://leetcode-cn.com/problems/sliding-window-maximum/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/sliding-window-maximum/)
|
||||
|
||||
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
|
||||
|
||||
@ -21,7 +21,7 @@ https://leetcode-cn.com/problems/sliding-window-maximum/
|
||||
进阶:
|
||||
|
||||
你能在线性时间复杂度内解决此题吗?
|
||||
|
||||
|
||||
<img src='https://code-thinking.cdn.bcebos.com/pics/239.滑动窗口最大值.png' width=600> </img></div>
|
||||
|
||||
提示:
|
||||
@ -104,7 +104,7 @@ public:
|
||||
|
||||
那么我们用什么数据结构来实现这个单调队列呢?
|
||||
|
||||
使用deque最为合适,在文章[栈与队列:来看看栈和队列不为人知的一面](https://mp.weixin.qq.com/s/HCXfQ_Bhpi63YaX0ZRSnAQ)中,我们就提到了常用的queue在没有指定容器的情况下,deque就是默认底层容器。
|
||||
使用deque最为合适,在文章[栈与队列:来看看栈和队列不为人知的一面](https://programmercarl.com/栈与队列理论基础.html)中,我们就提到了常用的queue在没有指定容器的情况下,deque就是默认底层容器。
|
||||
|
||||
基于刚刚说过的单调队列pop和push的规则,代码不难实现,如下:
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 242.有效的字母异位词
|
||||
|
||||
https://leetcode-cn.com/problems/valid-anagram/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/valid-anagram/)
|
||||
|
||||
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
|
||||
|
||||
@ -35,7 +35,7 @@ https://leetcode-cn.com/problems/valid-anagram/
|
||||
|
||||
**数组其实就是一个简单哈希表**,而且这道题目中字符串只有小写字符,那么就可以定义一个数组,来记录字符串s里字符出现的次数。
|
||||
|
||||
如果对哈希表的理论基础关于数组,set,map不了解的话可以看这篇:[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)
|
||||
如果对哈希表的理论基础关于数组,set,map不了解的话可以看这篇:[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)
|
||||
|
||||
需要定义一个多大的数组呢,定一个数组叫做record,大小为26 就可以了,初始化为0,因为字符a到字符z的ASCII也是26个连续的数值。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
# 257. 二叉树的所有路径
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/binary-tree-paths/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/binary-tree-paths/)
|
||||
|
||||
给定一个二叉树,返回所有从根节点到叶子节点的路径。
|
||||
|
||||
@ -270,7 +270,7 @@ if (cur->right) {
|
||||
## 迭代法
|
||||
|
||||
|
||||
至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)和[二叉树:前中后序迭代方式统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)。
|
||||
至于非递归的方式,我们可以依然可以使用前序遍历的迭代方式来模拟遍历路径的过程,对该迭代方式不了解的同学,可以看文章[二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:前中后序迭代方式统一写法](https://programmercarl.com/二叉树的统一迭代法.html)。
|
||||
|
||||
这里除了模拟递归需要一个栈,同时还需要一个栈来存放对应的遍历路径。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 279.完全平方数
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/perfect-squares/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/perfect-squares/)
|
||||
|
||||
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
**我来把题目翻译一下:完全平方数就是物品(可以无限件使用),凑个正整数n就是背包,问凑满这个背包最少有多少物品?**
|
||||
|
||||
感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)就是一样一样的!
|
||||
感受出来了没,这么浓厚的完全背包氛围,而且和昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)就是一样一样的!
|
||||
|
||||
动规五部曲分析如下:
|
||||
|
||||
@ -70,7 +70,7 @@ dp[0]表示 和为0的完全平方数的最小数量,那么dp[0]一定是0。
|
||||
|
||||
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
|
||||
|
||||
在[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ)中我们就深入探讨了这个问题,本题也是一样的,是求最小数!
|
||||
在[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html)中我们就深入探讨了这个问题,本题也是一样的,是求最小数!
|
||||
|
||||
**所以本题外层for遍历背包,里层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的!**
|
||||
|
||||
@ -146,7 +146,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://mp.weixin.qq.com/s/dyk-xNilHzNtVdPPLObSeQ),今天这道就非常简单了,一样的套路一样的味道。
|
||||
如果大家认真做了昨天的题目[动态规划:322. 零钱兑换](https://programmercarl.com/0322.零钱兑换.html),今天这道就非常简单了,一样的套路一样的味道。
|
||||
|
||||
但如果没有按照「代码随想录」的题目顺序来做的话,做动态规划或者做背包问题,上来就做这道题,那还是挺难的!
|
||||
|
||||
@ -161,7 +161,6 @@ public:
|
||||
Java:
|
||||
```Java
|
||||
class Solution {
|
||||
// 版本一,先遍历物品, 再遍历背包
|
||||
public int numSquares(int n) {
|
||||
int max = Integer.MAX_VALUE;
|
||||
int[] dp = new int[n + 1];
|
||||
@ -171,9 +170,7 @@ class Solution {
|
||||
}
|
||||
//当和为0时,组合的个数为0
|
||||
dp[0] = 0;
|
||||
// 遍历物品
|
||||
for (int i = 1; i * i <= n; i++) {
|
||||
// 遍历背包
|
||||
for (int j = i * i; j <= n; j++) {
|
||||
if (dp[j - i * i] != max) {
|
||||
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
|
||||
@ -183,28 +180,6 @@ class Solution {
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
|
||||
class Solution {
|
||||
// 版本二, 先遍历背包, 再遍历物品
|
||||
public int numSquares(int n) {
|
||||
int max = Integer.MAX_VALUE;
|
||||
int[] dp = new int[n + 1];
|
||||
// 初始化
|
||||
for (int j = 0; j <= n; j++) {
|
||||
dp[j] = max;
|
||||
}
|
||||
// 当和为0时,组合的个数为0
|
||||
dp[0] = 0;
|
||||
// 遍历背包
|
||||
for (int j = 1; j <= n; j++) {
|
||||
// 遍历物品
|
||||
for (int i = 1; i * i <= j; i++) {
|
||||
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
|
||||
}
|
||||
}
|
||||
return dp[n];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
@ -212,7 +187,7 @@ Python:
|
||||
```python3
|
||||
class Solution:
|
||||
def numSquares(self, n: int) -> int:
|
||||
'''版本一,先遍历背包, 再遍历物品'''
|
||||
'''版本一'''
|
||||
# 初始化
|
||||
nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
|
||||
dp = [10**4]*(n + 1)
|
||||
@ -226,7 +201,7 @@ class Solution:
|
||||
return dp[n]
|
||||
|
||||
def numSquares1(self, n: int) -> int:
|
||||
'''版本二, 先遍历物品, 再遍历背包'''
|
||||
'''版本二'''
|
||||
# 初始化
|
||||
nums = [i**2 for i in range(1, n + 1) if i**2 <= n]
|
||||
dp = [10**4]*(n + 1)
|
||||
@ -242,22 +217,6 @@ class Solution:
|
||||
Python3:
|
||||
```python
|
||||
class Solution:
|
||||
'''版本一,先遍历背包, 再遍历物品'''
|
||||
def numSquares(self, n: int) -> int:
|
||||
dp = [n] * (n + 1)
|
||||
dp[0] = 0
|
||||
# 遍历背包
|
||||
for j in range(1, n+1):
|
||||
for i in range(1, n):
|
||||
num = i ** 2
|
||||
if num > j: break
|
||||
# 遍历物品
|
||||
if j - num >= 0:
|
||||
dp[j] = min(dp[j], dp[j - num] + 1)
|
||||
return dp[n]
|
||||
|
||||
class Solution:
|
||||
'''版本二, 先遍历物品, 再遍历背包'''
|
||||
def numSquares(self, n: int) -> int:
|
||||
# 初始化
|
||||
# 组成和的完全平方数的最多个数,就是只用1构成
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
# 283. 移动零
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/move-zeroes/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/move-zeroes/)
|
||||
|
||||
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
|
||||
|
||||
@ -26,13 +26,13 @@
|
||||
|
||||
# 思路
|
||||
|
||||
做这道题目之前,大家可以做一做[27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)
|
||||
做这道题目之前,大家可以做一做[27.移除元素](https://programmercarl.com/0027.移除元素.html)
|
||||
|
||||
这道题目,使用暴力的解法,可以两层for循环,模拟数组删除元素(也就是向前覆盖)的过程。
|
||||
|
||||
好了,我们说一说双指针法,大家如果对双指针还不熟悉,可以看我的这篇总结[双指针法:总结篇!](https://mp.weixin.qq.com/s/PLfYLuUIGDR6xVRQ_jTrmg)。
|
||||
好了,我们说一说双指针法,大家如果对双指针还不熟悉,可以看我的这篇总结[双指针法:总结篇!](https://programmercarl.com/双指针总结.html)。
|
||||
|
||||
双指针法在数组移除元素中,可以达到O(n)的时间复杂度,在[27.移除元素](https://mp.weixin.qq.com/s/RMkulE4NIb6XsSX83ra-Ww)里已经详细讲解了,那么本题和移除元素其实是一个套路。
|
||||
双指针法在数组移除元素中,可以达到O(n)的时间复杂度,在[27.移除元素](https://programmercarl.com/0027.移除元素.html)里已经详细讲解了,那么本题和移除元素其实是一个套路。
|
||||
|
||||
**相当于对整个数组移除元素0,然后slowIndex之后都是移除元素0的冗余元素,把这些元素都赋值为0就可以了**。
|
||||
|
||||
|
@ -8,13 +8,13 @@
|
||||
|
||||
## 300.最长递增子序列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/longest-increasing-subsequence/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/longest-increasing-subsequence/)
|
||||
|
||||
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
|
||||
|
||||
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
输入:nums = [10,9,2,5,3,7,101,18]
|
||||
输出:4
|
||||
@ -27,7 +27,7 @@
|
||||
示例 3:
|
||||
输入:nums = [7,7,7,7,7,7,7]
|
||||
输出:1
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
* 1 <= nums.length <= 2500
|
||||
@ -215,9 +215,9 @@ const lengthOfLIS = (nums) => {
|
||||
1. if(nums[i]>list[len-1],此时,list中子序列长度为1到len的对应的最右端最小值不变,并新增长度为len+1的子序列,最右端的最小值为nums[i],时间复杂度O(1);
|
||||
|
||||
2. if(nums[i]<=list[len-1]),此时,我们可以在0到len-1范围内找到k,list[k]为>=nums[i]的最小值,由于list单调递增,所以我们可以使用二分搜索在O(logn)的时间复杂度内找到k。
|
||||
1. 对于0<=j<k,list[j]<nums[i]恒成立,对应list[j]的值不需要更新。
|
||||
2. 对于list[k],其值更新为nums[i],因为原本list[k]对应的子序列的倒数第二项的值可以=list[k-1]<nums[i]。
|
||||
3. 对于k<j<=len-1,对应的list[j]不需要更新。因为这些list[j]对应的子序列的倒数第二项的值>nums[i];
|
||||
1. 对于0<=j<k,list[j]<nums[i]恒成立,对应list[j]的值不需要更新。
|
||||
2. 对于list[k],其值更新为nums[i],因为原本list[k]对应的子序列的倒数第二项的值可以=list[k-1]<nums[i]。
|
||||
3. 对于k<j<=len-1,对应的list[j]不需要更新。因为这些list[j]对应的子序列的倒数第二项的值>nums[i];
|
||||
|
||||
3. 综上,算法时间复杂度为O(nlogn),空间复杂度为O(n),需要O(n)的空间保存list。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 309.最佳买卖股票时机含冷冻期
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)
|
||||
|
||||
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
|
||||
|
||||
@ -25,12 +25,12 @@
|
||||
|
||||
## 思路
|
||||
|
||||
> 之前我们在[动态规划:最佳买卖股票时机含冷冻期](https://mp.weixin.qq.com/s/IgC0iWWCDpYL9ZbTHGHgfw)讲过一次这道题目,讲解的过程感觉不是很严谨,和录友们也聊过这个问题,本着对大家负责的态度,有问题的地方我都会及时纠正,所以重新发文讲解一下。
|
||||
> 之前我们在[动态规划:最佳买卖股票时机含冷冻期](https://programmercarl.com/0309.最佳买卖股票时机含冷冻期.html)讲过一次这道题目,讲解的过程感觉不是很严谨,和录友们也聊过这个问题,本着对大家负责的态度,有问题的地方我都会及时纠正,所以重新发文讲解一下。
|
||||
|
||||
相对于[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w),本题加上了一个冷冻期
|
||||
相对于[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html),本题加上了一个冷冻期
|
||||
|
||||
|
||||
在[动态规划:122.买卖股票的最佳时机II](https://mp.weixin.qq.com/s/d4TRWFuhaY83HPa6t5ZL-w) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。
|
||||
在[动态规划:122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II(动态规划).html) 中有两个状态,持有股票后的最多现金,和不持有股票的最多现金。
|
||||
|
||||
动规五部曲,分析如下:
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 322. 零钱兑换
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/coin-change/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/coin-change/)
|
||||
|
||||
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
|
||||
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
在[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中我们已经兑换一次零钱了,这次又要兑换,套路不一样!
|
||||
在[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中我们已经兑换一次零钱了,这次又要兑换,套路不一样!
|
||||
|
||||
题目中说每种硬币的数量是无限的,可以看出是典型的完全背包问题。
|
||||
|
||||
@ -91,7 +91,7 @@ dp[0] = 0;
|
||||
|
||||
**如果求排列数就是外层for遍历背包,内层for循环遍历物品**。
|
||||
|
||||
在动态规划专题我们讲过了求组合数是[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ),求排列数是[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)。
|
||||
在动态规划专题我们讲过了求组合数是[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html),求排列数是[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)。
|
||||
|
||||
**所以本题的两个for循环的关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以的!**
|
||||
|
||||
@ -166,7 +166,7 @@ public:
|
||||
|
||||
那么这篇文章就把遍历顺序分析的清清楚楚。
|
||||
|
||||
[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中求的是组合数,[动态规划:377. 组合总和 Ⅳ](https://mp.weixin.qq.com/s/Iixw0nahJWQgbqVNk8k6gA)中求的是排列数。
|
||||
[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中求的是组合数,[动态规划:377. 组合总和 Ⅳ](https://programmercarl.com/0377.组合总和Ⅳ.html)中求的是排列数。
|
||||
|
||||
**而本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以!**
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 332.重新安排行程
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/reconstruct-itinerary/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/reconstruct-itinerary/)
|
||||
|
||||
给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
* 所有的机场都用三个大写字母表示(机场代码)。
|
||||
* 假定所有机票至少存在一种合理的行程。
|
||||
* 所有的机票必须都用一次 且 只能用一次。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
输入:[["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
|
||||
@ -36,7 +36,7 @@
|
||||
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
|
||||
|
||||
|
||||
这道题目还是很难的,之前我们用回溯法解决了如下问题:[组合问题](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ),[分割问题](https://mp.weixin.qq.com/s/v--VmA8tp9vs4bXCqHhBuA),[子集问题](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA),[排列问题](https://mp.weixin.qq.com/s/SCOjeMX1t41wcvJq49GhMw)。
|
||||
这道题目还是很难的,之前我们用回溯法解决了如下问题:[组合问题](https://programmercarl.com/0077.组合.html),[分割问题](https://programmercarl.com/0093.复原IP地址.html),[子集问题](https://programmercarl.com/0078.子集.html),[排列问题](https://programmercarl.com/0046.全排列.html)。
|
||||
|
||||
直觉上来看 这道题和回溯法没有什么关系,更像是图论中的深度优先搜索。
|
||||
|
||||
@ -69,7 +69,7 @@
|
||||
|
||||
一个机场映射多个机场,机场之间要靠字母序排列,一个机场映射多个机场,可以使用std::unordered_map,如果让多个机场之间再有顺序的话,就是用std::map 或者std::multimap 或者 std::multiset。
|
||||
|
||||
如果对map 和 set 的实现机制不太了解,也不清楚为什么 map、multimap就是有序的同学,可以看这篇文章[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)。
|
||||
如果对map 和 set 的实现机制不太了解,也不清楚为什么 map、multimap就是有序的同学,可以看这篇文章[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)。
|
||||
|
||||
这样存放映射关系可以定义为 `unordered_map<string, multiset<string>> targets` 或者 `unordered_map<string, map<string, int>> targets`。
|
||||
|
||||
@ -140,7 +140,7 @@ bool backtracking(int ticketNum, vector<string>& result) {
|
||||
|
||||

|
||||
|
||||
所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://mp.weixin.qq.com/s/6TWAVjxQ34kVqROWgcRFOg)详细介绍过。
|
||||
所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)详细介绍过。
|
||||
|
||||
当然本题的targets和result都需要初始化,代码如下:
|
||||
```
|
||||
@ -164,7 +164,7 @@ if (result.size() == ticketNum + 1) {
|
||||
}
|
||||
```
|
||||
|
||||
已经看习惯回溯法代码的同学,到叶子节点了习惯性的想要收集结果,但发现并不需要,本题的result相当于 [回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中的path,也就是本题的result就是记录路径的(就一条),在如下单层搜索的逻辑中result就添加元素了。
|
||||
已经看习惯回溯法代码的同学,到叶子节点了习惯性的想要收集结果,但发现并不需要,本题的result相当于 [回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中的path,也就是本题的result就是记录路径的(就一条),在如下单层搜索的逻辑中result就添加元素了。
|
||||
|
||||
* 单层搜索的逻辑
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 337.打家劫舍 III
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/house-robber-iii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/house-robber-iii/)
|
||||
|
||||
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
这道题目和 [198.打家劫舍](https://mp.weixin.qq.com/s/UZ31WdLEEFmBegdgLkJ8Dw),[213.打家劫舍II](https://mp.weixin.qq.com/s/kKPx4HpH3RArbRcxAVHbeQ)也是如出一辙,只不过这个换成了树。
|
||||
这道题目和 [198.打家劫舍](https://programmercarl.com/0198.打家劫舍.html),[213.打家劫舍II](https://programmercarl.com/0213.打家劫舍II.html)也是如出一辙,只不过这个换成了树。
|
||||
|
||||
如果对树的遍历不够熟悉的话,那本题就有难度了。
|
||||
|
||||
@ -210,7 +210,7 @@ public:
|
||||
|
||||
只不过平时我们习惯了在一维数组或者二维数组上推导公式,一下子换成了树,就需要对树的遍历方式足够了解!
|
||||
|
||||
大家还记不记得我在讲解贪心专题的时候,讲到这道题目:[贪心算法:我要监控二叉树!](https://mp.weixin.qq.com/s/kCxlLLjWKaE6nifHC3UL2Q),这也是贪心算法在树上的应用。**那我也可以把这个算法起一个名字,叫做树形贪心**,哈哈哈
|
||||
大家还记不记得我在讲解贪心专题的时候,讲到这道题目:[贪心算法:我要监控二叉树!](https://programmercarl.com/0968.监控二叉树.html),这也是贪心算法在树上的应用。**那我也可以把这个算法起一个名字,叫做树形贪心**,哈哈哈
|
||||
|
||||
“树形贪心”词汇从此诞生,来自「代码随想录」
|
||||
|
||||
|
@ -8,14 +8,15 @@
|
||||
|
||||
## 343. 整数拆分
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/integer-break/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/integer-break/)
|
||||
|
||||
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
|
||||
|
||||
示例 1:
|
||||
输入: 2
|
||||
输出: 1
|
||||
解释: 2 = 1 + 1, 1 × 1 = 1。
|
||||
|
||||
\解释: 2 = 1 + 1, 1 × 1 = 1。
|
||||
|
||||
示例 2:
|
||||
输入: 10
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
# 344.反转字符串
|
||||
|
||||
https://leetcode-cn.com/problems/reverse-string/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/reverse-string/)
|
||||
|
||||
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
|
||||
|
||||
@ -55,7 +55,7 @@ https://leetcode-cn.com/problems/reverse-string/
|
||||
|
||||
接下来再来讲一下如何解决反转字符串的问题。
|
||||
|
||||
大家应该还记得,我们已经讲过了[206.反转链表](https://mp.weixin.qq.com/s/ckEvIVGcNLfrz6OLOMoT0A)。
|
||||
大家应该还记得,我们已经讲过了[206.反转链表](https://programmercarl.com/0206.翻转链表.html)。
|
||||
|
||||
在反转链表中,使用了双指针的方法。
|
||||
|
||||
@ -63,7 +63,7 @@ https://leetcode-cn.com/problems/reverse-string/
|
||||
|
||||
因为字符串也是一种数组,所以元素在内存中是连续分布,这就决定了反转链表和反转字符串方式上还是有所差异的。
|
||||
|
||||
如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://mp.weixin.qq.com/s/fDGMmLrW7ZHlzkzlf_dZkw),[必须掌握的数组理论知识](https://mp.weixin.qq.com/s/c2KABb-Qgg66HrGf8z-8Og)。
|
||||
如果对数组和链表原理不清楚的同学,可以看这两篇,[关于链表,你该了解这些!](https://programmercarl.com/链表理论基础.html),[必须掌握的数组理论知识](https://programmercarl.com/数组理论基础.html)。
|
||||
|
||||
对于字符串,我们定义两个指针(也可以说是索引下表),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。
|
||||
|
||||
@ -162,14 +162,21 @@ class Solution:
|
||||
Do not return anything, modify s in-place instead.
|
||||
"""
|
||||
left, right = 0, len(s) - 1
|
||||
|
||||
# 该方法已经不需要判断奇偶数,经测试后时间空间复杂度比用 for i in range(right//2)更低
|
||||
# 推荐该写法,更加通俗易懂
|
||||
while left < right:
|
||||
while(left < right):
|
||||
s[left], s[right] = s[right], s[left]
|
||||
left += 1
|
||||
right -= 1
|
||||
|
||||
|
||||
# 下面的写法更加简洁,但是都是同样的算法
|
||||
# class Solution:
|
||||
# def reverseString(self, s: List[str]) -> None:
|
||||
# """
|
||||
# Do not return anything, modify s in-place instead.
|
||||
# """
|
||||
# 不需要判别是偶数个还是奇数个序列,因为奇数个的时候,中间那个不需要交换就可
|
||||
# for i in range(len(s)//2):
|
||||
# s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
|
||||
# return s
|
||||
```
|
||||
|
||||
Go:
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
# 347.前 K 个高频元素
|
||||
|
||||
https://leetcode-cn.com/problems/top-k-frequent-elements/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/top-k-frequent-elements/)
|
||||
|
||||
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
## 349. 两个数组的交集
|
||||
|
||||
https://leetcode-cn.com/problems/intersection-of-two-arrays/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/intersection-of-two-arrays/)
|
||||
|
||||
题意:给定两个数组,编写一个函数来计算它们的交集。
|
||||
|
||||
@ -32,7 +32,7 @@ https://leetcode-cn.com/problems/intersection-of-two-arrays/
|
||||
|
||||
这道题用暴力的解法时间复杂度是O(n^2),那来看看使用哈希法进一步优化。
|
||||
|
||||
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)
|
||||
那么用数组来做哈希表也是不错的选择,例如[242. 有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)
|
||||
|
||||
但是要注意,**使用数组来做哈希的题目,是因为题目都限制了数值的大小。**
|
||||
|
||||
@ -143,26 +143,6 @@ func intersection(nums1 []int, nums2 []int) []int {
|
||||
return res
|
||||
}
|
||||
```
|
||||
```golang
|
||||
//优化版,利用set,减少count统计
|
||||
func intersection(nums1 []int, nums2 []int) []int {
|
||||
set:=make(map[int]struct{},0)
|
||||
res:=make([]int,0)
|
||||
for _,v:=range nums1{
|
||||
if _,ok:=set[v];!ok{
|
||||
set[v]=struct{}{}
|
||||
}
|
||||
}
|
||||
for _,v:=range nums2{
|
||||
//如果存在于上一个数组中,则加入结果集,并清空该set值
|
||||
if _,ok:=set[v];ok{
|
||||
res=append(res,v)
|
||||
delete(set, v)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
javaScript:
|
||||
|
||||
|
@ -7,11 +7,11 @@
|
||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
|
||||
> 本周讲解了[贪心理论基础](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg),以及第一道贪心的题目:[贪心算法:分发饼干](https://mp.weixin.qq.com/s/YSuLIAYyRGlyxbp9BNC1uw),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。
|
||||
> 本周讲解了[贪心理论基础](https://programmercarl.com/贪心算法理论基础.html),以及第一道贪心的题目:[贪心算法:分发饼干](https://programmercarl.com/0455.分发饼干.html),可能会给大家一种贪心算法比较简单的错觉,好了,接下来几天的题目难度要上来了,哈哈。
|
||||
|
||||
## 376. 摆动序列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/wiggle-subsequence/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/wiggle-subsequence/)
|
||||
|
||||
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 377. 组合总和 Ⅳ
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/combination-sum-iv/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/combination-sum-iv/)
|
||||
|
||||
难度:中等
|
||||
|
||||
@ -43,7 +43,7 @@ target = 4
|
||||
|
||||
排列强调顺序,(1,5)和(5,1)是两个不同的排列。
|
||||
|
||||
大家在公众号里学习回溯算法专题的时候,一定做过这两道题目[回溯算法:39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)和[回溯算法:40.组合总和II](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)会感觉这两题和本题很像!
|
||||
大家在公众号里学习回溯算法专题的时候,一定做过这两道题目[回溯算法:39.组合总和](https://programmercarl.com/0039.组合总和.html)和[回溯算法:40.组合总和II](https://programmercarl.com/0040.组合总和II.html)会感觉这两题和本题很像!
|
||||
|
||||
但其本质是本题求的是排列总和,而且仅仅是求排列总和的个数,并不是把所有的排列都列出来。
|
||||
|
||||
@ -61,7 +61,7 @@ dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导
|
||||
|
||||
因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。
|
||||
|
||||
在[动态规划:494.目标和](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw) 和 [动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)中我们已经讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
|
||||
在[动态规划:494.目标和](https://programmercarl.com/0494.目标和.html) 和 [动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中我们已经讲过了,求装满背包有几种方法,递推公式一般都是dp[i] += dp[i - nums[j]];
|
||||
|
||||
本题也一样。
|
||||
|
||||
@ -87,7 +87,7 @@ dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导
|
||||
|
||||
本题要求的是排列,那么这个for循环嵌套的顺序可以有说法了。
|
||||
|
||||
在[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ) 中就已经讲过了。
|
||||
在[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html) 中就已经讲过了。
|
||||
|
||||
**如果求组合数就是外层for循环遍历物品,内层for遍历背包**。
|
||||
|
||||
@ -134,7 +134,7 @@ C++测试用例有超过两个树相加超过int的数据,所以需要在if里
|
||||
|
||||
**求装满背包有几种方法,递归公式都是一样的,没有什么差别,但关键在于遍历顺序!**
|
||||
|
||||
本题与[动态规划:518.零钱兑换II](https://mp.weixin.qq.com/s/PlowDsI4WMBOzf3q80AksQ)就是一个鲜明的对比,一个是求排列,一个是求组合,遍历顺序完全不同。
|
||||
本题与[动态规划:518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)就是一个鲜明的对比,一个是求排列,一个是求组合,遍历顺序完全不同。
|
||||
|
||||
如果对遍历顺序没有深度理解的话,做这种完全背包的题目会很懵逼,即使题目刷过了可能也不太清楚具体是怎么过的。
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
# 383. 赎金信
|
||||
|
||||
https://leetcode-cn.com/problems/ransom-note/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/ransom-note/)
|
||||
|
||||
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
|
||||
|
||||
@ -28,7 +28,7 @@ canConstruct("aa", "aab") -> true
|
||||
|
||||
## 思路
|
||||
|
||||
这道题目和[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)很像,[242.有效的字母异位词](https://mp.weixin.qq.com/s/ffS8jaVFNUWyfn_8T31IdA)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
|
||||
这道题目和[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)很像,[242.有效的字母异位词](https://programmercarl.com/0242.有效的字母异位词.html)相当于求 字符串a 和 字符串b 是否可以相互组成 ,而这道题目是求 字符串a能否组成字符串b,而不用管字符串b 能不能组成字符串a。
|
||||
|
||||
本题判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成,但是这里需要注意两点。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 392.判断子序列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/is-subsequence/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/is-subsequence/)
|
||||
|
||||
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 404.左叶子之和
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/sum-of-left-leaves/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/sum-of-left-leaves/)
|
||||
|
||||
计算给定二叉树的所有左叶子之和。
|
||||
|
||||
@ -119,7 +119,7 @@ public:
|
||||
## 迭代法
|
||||
|
||||
|
||||
本题迭代法使用前中后序都是可以的,只要把左叶子节点统计出来,就可以了,那么参考文章 [二叉树:听说递归能做的,栈也能做!](https://mp.weixin.qq.com/s/OH7aCVJ5-Gi32PkNCoZk4A)和[二叉树:迭代法统一写法](https://mp.weixin.qq.com/s/ATQMPCpBlaAgrqdLDMVPZA)中的写法,可以写出一个前序遍历的迭代法。
|
||||
本题迭代法使用前中后序都是可以的,只要把左叶子节点统计出来,就可以了,那么参考文章 [二叉树:听说递归能做的,栈也能做!](https://programmercarl.com/二叉树的迭代遍历.html)和[二叉树:迭代法统一写法](https://programmercarl.com/二叉树的统一迭代法.html)中的写法,可以写出一个前序遍历的迭代法。
|
||||
|
||||
判断条件都是一样的,代码如下:
|
||||
|
||||
@ -326,7 +326,7 @@ var sumOfLeftLeaves = function(root) {
|
||||
}
|
||||
return nodesSum(root);
|
||||
};
|
||||
```
|
||||
```
|
||||
|
||||
**迭代法**
|
||||
```javascript
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 406.根据身高重建队列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/queue-reconstruction-by-height/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/queue-reconstruction-by-height/)
|
||||
|
||||
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
|
||||
|
||||
@ -43,9 +43,9 @@
|
||||
|
||||
本题有两个维度,h和k,看到这种题目一定要想如何确定一个维度,然后在按照另一个维度重新排列。
|
||||
|
||||
其实如果大家认真做了[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ),就会发现和此题有点点的像。
|
||||
其实如果大家认真做了[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html),就会发现和此题有点点的像。
|
||||
|
||||
在[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。
|
||||
在[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。
|
||||
|
||||
**如果两个维度一起考虑一定会顾此失彼**。
|
||||
|
||||
@ -76,11 +76,11 @@
|
||||
|
||||
一些同学可能也会疑惑,你怎么知道局部最优就可以推出全局最优呢? 有数学证明么?
|
||||
|
||||
在贪心系列开篇词[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)中,我已经讲过了这个问题了。
|
||||
在贪心系列开篇词[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中,我已经讲过了这个问题了。
|
||||
|
||||
刷题或者面试的时候,手动模拟一下感觉可以局部最优推出整体最优,而且想不到反例,那么就试一试贪心,至于严格的数学证明,就不在讨论范围内了。
|
||||
|
||||
如果没有读过[关于贪心算法,你该了解这些!](https://mp.weixin.qq.com/s/O935TaoHE9Eexwe_vSbRAg)的同学建议读一下,相信对贪心就有初步的了解了。
|
||||
如果没有读过[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)的同学建议读一下,相信对贪心就有初步的了解了。
|
||||
|
||||
回归本题,整个插入过程如下:
|
||||
|
||||
@ -157,15 +157,15 @@ public:
|
||||
|
||||
大家可以把两个版本的代码提交一下试试,就可以发现其差别了!
|
||||
|
||||
关于本题使用数组还是使用链表的性能差异,我在[贪心算法:根据身高重建队列(续集)](https://mp.weixin.qq.com/s/K-pRN0lzR-iZhoi-1FgbSQ)中详细讲解了一波
|
||||
关于本题使用数组还是使用链表的性能差异,我在[贪心算法:根据身高重建队列(续集)](https://programmercarl.com/根据身高重建队列(vector原理讲解).html)中详细讲解了一波
|
||||
|
||||
## 总结
|
||||
|
||||
关于出现两个维度一起考虑的情况,我们已经做过两道题目了,另一道就是[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)。
|
||||
关于出现两个维度一起考虑的情况,我们已经做过两道题目了,另一道就是[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html)。
|
||||
|
||||
**其技巧都是确定一边然后贪心另一边,两边一起考虑,就会顾此失彼**。
|
||||
|
||||
这道题目可以说比[135. 分发糖果](https://mp.weixin.qq.com/s/8MwlgFfvaNYmjGwjuMlETQ)难不少,其贪心的策略也是比较巧妙。
|
||||
这道题目可以说比[135. 分发糖果](https://programmercarl.com/0135.分发糖果.html)难不少,其贪心的策略也是比较巧妙。
|
||||
|
||||
最后我给出了两个版本的代码,可以明显看是使用C++中的list(底层链表实现)比vector(数组)效率高得多。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 416. 分割等和子集
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/partition-equal-subset-sum/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/partition-equal-subset-sum/)
|
||||
|
||||
题目难易:中等
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
输入: [1, 5, 11, 5]
|
||||
输出: true
|
||||
解释: 数组可以分割成 [1, 5, 5] 和 [11].
|
||||
|
||||
|
||||
示例 2:
|
||||
输入: [1, 2, 3, 5]
|
||||
输出: false
|
||||
@ -47,8 +47,8 @@
|
||||
|
||||
如果对01背包不够了解,建议仔细看完如下两篇:
|
||||
|
||||
* [动态规划:关于01背包问题,你该了解这些!](https://mp.weixin.qq.com/s/FwIiPPmR18_AJO5eiidT6w)
|
||||
* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)
|
||||
* [动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)
|
||||
* [动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)
|
||||
|
||||
## 01背包问题
|
||||
|
||||
@ -114,7 +114,7 @@ vector<int> dp(10001, 0);
|
||||
|
||||
4. 确定遍历顺序
|
||||
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 435. 无重叠区间
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/non-overlapping-intervals/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/non-overlapping-intervals/)
|
||||
|
||||
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
|
||||
|
||||
@ -122,9 +122,9 @@ public:
|
||||
|
||||
## 补充
|
||||
|
||||
本题其实和[452.用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)非常像,弓箭的数量就相当于是非交叉区间的数量,只要把弓箭那道题目代码里射爆气球的判断条件加个等号(认为[0,1][1,2]不是相邻区间),然后用总区间数减去弓箭数量 就是要移除的区间数量了。
|
||||
本题其实和[452.用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)非常像,弓箭的数量就相当于是非交叉区间的数量,只要把弓箭那道题目代码里射爆气球的判断条件加个等号(认为[0,1][1,2]不是相邻区间),然后用总区间数减去弓箭数量 就是要移除的区间数量了。
|
||||
|
||||
把[452.用最少数量的箭引爆气球](https://mp.weixin.qq.com/s/HxVAJ6INMfNKiGwI88-RFw)代码稍做修改,就可以AC本题。
|
||||
把[452.用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html)代码稍做修改,就可以AC本题。
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 450.删除二叉搜索树中的节点
|
||||
|
||||
题目链接: https://leetcode-cn.com/problems/delete-node-in-a-bst/
|
||||
[力扣题目链接]( https://leetcode-cn.com/problems/delete-node-in-a-bst/)
|
||||
|
||||
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
|
||||
* 确定递归函数参数以及返回值
|
||||
|
||||
说道递归函数的返回值,在[二叉树:搜索树中的插入操作](https://mp.weixin.qq.com/s/lwKkLQcfbCNX2W-5SOeZEA)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。
|
||||
说道递归函数的返回值,在[二叉树:搜索树中的插入操作](https://programmercarl.com/0701.二叉搜索树中的插入操作.html)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 452. 用最少数量的箭引爆气球
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/)
|
||||
|
||||
在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。
|
||||
|
||||
|
@ -11,8 +11,7 @@
|
||||
|
||||
# 第454题.四数相加II
|
||||
|
||||
|
||||
https://leetcode-cn.com/problems/4sum-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/4sum-ii/)
|
||||
|
||||
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
|
||||
|
||||
@ -35,9 +34,9 @@ D = [ 0, 2]
|
||||
|
||||
# 思路
|
||||
|
||||
本题咋眼一看好像和[0015.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A),[0018.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)差不多,其实差很多。
|
||||
本题咋眼一看好像和[0015.三数之和](https://programmercarl.com/0015.三数之和.html),[0018.四数之和](https://programmercarl.com/0018.四数之和.html)差不多,其实差很多。
|
||||
|
||||
**本题是使用哈希法的经典题目,而[0015.三数之和](https://mp.weixin.qq.com/s/r5cgZFu0tv4grBAexdcd8A),[0018.四数之和](https://mp.weixin.qq.com/s/nQrcco8AZJV1pAOVjeIU_g)并不合适使用哈希法**,因为三数之和和四数之和这两道题目使用哈希法在不超时的情况下做到对结果去重是很困难的,很有多细节需要处理。
|
||||
**本题是使用哈希法的经典题目,而[0015.三数之和](https://programmercarl.com/0015.三数之和.html),[0018.四数之和](https://programmercarl.com/0018.四数之和.html)并不合适使用哈希法**,因为三数之和和四数之和这两道题目使用哈希法在不超时的情况下做到对结果去重是很困难的,很有多细节需要处理。
|
||||
|
||||
**而这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于题目18. 四数之和,题目15.三数之和,还是简单了不少!**
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 455.分发饼干
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/assign-cookies/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/assign-cookies/)
|
||||
|
||||
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
|
||||
|
||||
@ -165,7 +165,7 @@ func findContentChildren(g []int, s []int) int {
|
||||
|
||||
|
||||
Javascript:
|
||||
```Javascript
|
||||
```Javascript
|
||||
|
||||
var findContentChildren = function(g, s) {
|
||||
g = g.sort((a, b) => a - b)
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
# 459.重复的子字符串
|
||||
|
||||
https://leetcode-cn.com/problems/repeated-substring-pattern/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/repeated-substring-pattern/)
|
||||
|
||||
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
|
||||
|
||||
@ -41,11 +41,11 @@ https://leetcode-cn.com/problems/repeated-substring-pattern/
|
||||
* [帮你把KMP算法学个通透!(求next数组代码篇)](https://www.bilibili.com/video/BV1M5411j7Xx)
|
||||
|
||||
|
||||
我们在[字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)里提到了,在一个串中查找是否出现过另一个串,这是KMP的看家本领。
|
||||
我们在[字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html)里提到了,在一个串中查找是否出现过另一个串,这是KMP的看家本领。
|
||||
|
||||
那么寻找重复子串怎么也涉及到KMP算法了呢?
|
||||
|
||||
这里就要说一说next数组了,next 数组记录的就是最长相同前后缀( [字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg) 这里介绍了什么是前缀,什么是后缀,什么又是最长相同前后缀), 如果 next[len - 1] != -1,则说明字符串有最长相同的前后缀(就是字符串里的前缀子串和后缀子串相同的最长长度)。
|
||||
这里就要说一说next数组了,next 数组记录的就是最长相同前后缀( [字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html) 这里介绍了什么是前缀,什么是后缀,什么又是最长相同前后缀), 如果 next[len - 1] != -1,则说明字符串有最长相同的前后缀(就是字符串里的前缀子串和后缀子串相同的最长长度)。
|
||||
|
||||
最长相等前后缀的长度为:next[len - 1] + 1。
|
||||
|
||||
@ -137,11 +137,11 @@ public:
|
||||
|
||||
# 拓展
|
||||
|
||||
在[字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)中讲解KMP算法的基础理论,给出next数组究竟是如何来了,前缀表又是怎么回事,为什么要选择前缀表。
|
||||
在[字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html)中讲解KMP算法的基础理论,给出next数组究竟是如何来了,前缀表又是怎么回事,为什么要选择前缀表。
|
||||
|
||||
讲解一道KMP的经典题目,力扣:28. 实现 strStr(),判断文本串里是否出现过模式串,这里涉及到构造next数组的代码实现,以及使用next数组完成模式串与文本串的匹配过程。
|
||||
|
||||
后来很多同学反馈说:搞不懂前后缀,什么又是最长相同前后缀(最长公共前后缀我认为这个用词不准确),以及为什么前缀表要统一减一(右移)呢,不减一行不行?针对这些问题,我在[字符串:KMP算法精讲](https://mp.weixin.qq.com/s/MoRBHbS4hQXn7LcPdmHmIg)给出了详细的讲解。
|
||||
后来很多同学反馈说:搞不懂前后缀,什么又是最长相同前后缀(最长公共前后缀我认为这个用词不准确),以及为什么前缀表要统一减一(右移)呢,不减一行不行?针对这些问题,我在[字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html)给出了详细的讲解。
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
## 题目链接
|
||||
https://leetcode-cn.com/problems/island-perimeter/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/island-perimeter/)
|
||||
|
||||
## 思路
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 474.一和零
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/ones-and-zeroes/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/ones-and-zeroes/)
|
||||
|
||||
给你一个二进制字符串数组 strs 和两个整数 m 和 n 。
|
||||
|
||||
@ -84,13 +84,13 @@ dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1。
|
||||
|
||||
3. dp数组如何初始化
|
||||
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中已经讲解了,01背包的dp数组初始化为0就可以。
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中已经讲解了,01背包的dp数组初始化为0就可以。
|
||||
|
||||
因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖。
|
||||
|
||||
4. 确定遍历顺序
|
||||
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中,我们讲到了01背包为什么一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中,我们讲到了01背包为什么一定是外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历!
|
||||
|
||||
那么本题也是,物品就是strs里的字符串,背包容量就是题目描述中的m和n。
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 491.递增子序列
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/increasing-subsequences/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/increasing-subsequences/)
|
||||
|
||||
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
|
||||
|
||||
@ -33,11 +33,11 @@
|
||||
|
||||
这个递增子序列比较像是取有序的子集。而且本题也要求不能有相同的递增子序列。
|
||||
|
||||
这又是子集,又是去重,是不是不由自主的想起了刚刚讲过的[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)。
|
||||
这又是子集,又是去重,是不是不由自主的想起了刚刚讲过的[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)。
|
||||
|
||||
就是因为太像了,更要注意差别所在,要不就掉坑里了!
|
||||
|
||||
在[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)中我们是通过排序,再加一个标记数组来达到去重的目的。
|
||||
在[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中我们是通过排序,再加一个标记数组来达到去重的目的。
|
||||
|
||||
而本题求自增子序列,是不能对原数组经行排序的,排完序的数组都是自增子序列了。
|
||||
|
||||
@ -66,7 +66,7 @@ void backtracking(vector<int>& nums, int startIndex)
|
||||
|
||||
* 终止条件
|
||||
|
||||
本题其实类似求子集问题,也是要遍历树形结构找每一个节点,所以和[回溯算法:求子集问题!](https://mp.weixin.qq.com/s/NNRzX-vJ_pjK4qxohd_LtA)一样,可以不加终止条件,startIndex每次都会加1,并不会无限递归。
|
||||
本题其实类似求子集问题,也是要遍历树形结构找每一个节点,所以和[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)一样,可以不加终止条件,startIndex每次都会加1,并不会无限递归。
|
||||
|
||||
但本题收集结果有所不同,题目要求递增子序列大小至少为2,所以代码如下:
|
||||
|
||||
@ -184,7 +184,7 @@ public:
|
||||
|
||||
这份代码在leetcode上提交,要比版本一耗时要好的多。
|
||||
|
||||
**所以正如在[哈希表:总结篇!(每逢总结必经典)](https://mp.weixin.qq.com/s/1s91yXtarL-PkX07BfnwLg)中说的那样,数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如何数值范围小的话能用数组尽量用数组**。
|
||||
**所以正如在[哈希表:总结篇!(每逢总结必经典)](https://programmercarl.com/哈希表总结.html)中说的那样,数组,set,map都可以做哈希表,而且数组干的活,map和set都能干,但如何数值范围小的话能用数组尽量用数组**。
|
||||
|
||||
|
||||
|
||||
@ -192,7 +192,7 @@ public:
|
||||
|
||||
本题题解清一色都说是深度优先搜索,但我更倾向于说它用回溯法,而且本题我也是完全使用回溯法的逻辑来分析的。
|
||||
|
||||
相信大家在本题中处处都能看到是[回溯算法:求子集问题(二)](https://mp.weixin.qq.com/s/WJ4JNDRJgsW3eUN72Hh3uQ)的身影,但处处又都是陷阱。
|
||||
相信大家在本题中处处都能看到是[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)的身影,但处处又都是陷阱。
|
||||
|
||||
**对于养成思维定式或者套模板套嗨了的同学,这道题起到了很好的警醒作用。更重要的是拓展了大家的思路!**
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 494. 目标和
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/target-sum/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/target-sum/)
|
||||
|
||||
难度:中等
|
||||
|
||||
@ -19,15 +19,15 @@
|
||||
|
||||
示例:
|
||||
|
||||
输入:nums: [1, 1, 1, 1, 1], S: 3
|
||||
输出:5
|
||||
输入:nums: [1, 1, 1, 1, 1], S: 3
|
||||
输出:5
|
||||
|
||||
解释:
|
||||
-1+1+1+1+1 = 3
|
||||
+1-1+1+1+1 = 3
|
||||
+1+1-1+1+1 = 3
|
||||
+1+1+1-1+1 = 3
|
||||
+1+1+1+1-1 = 3
|
||||
解释:
|
||||
-1+1+1+1+1 = 3
|
||||
+1-1+1+1+1 = 3
|
||||
+1+1-1+1+1 = 3
|
||||
+1+1+1-1+1 = 3
|
||||
+1+1+1+1-1 = 3
|
||||
|
||||
一共有5种方法让最终目标和为3。
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
如果跟着「代码随想录」一起学过[回溯算法系列](https://mp.weixin.qq.com/s/r73thpBnK1tXndFDtlsdCQ)的录友,看到这道题,应该有一种直觉,就是感觉好像回溯法可以爆搜出来。
|
||||
如果跟着「代码随想录」一起学过[回溯算法系列](https://programmercarl.com/回溯总结.html)的录友,看到这道题,应该有一种直觉,就是感觉好像回溯法可以爆搜出来。
|
||||
|
||||
事实确实如此,下面我也会给出相应的代码,只不过会超时,哈哈。
|
||||
|
||||
@ -59,7 +59,7 @@ target是固定的,sum是固定的,left就可以求出来。
|
||||
|
||||
## 回溯算法
|
||||
|
||||
在回溯算法系列中,一起学过这道题目[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)的录友应该感觉很熟悉,这不就是组合总和问题么?
|
||||
在回溯算法系列中,一起学过这道题目[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)的录友应该感觉很熟悉,这不就是组合总和问题么?
|
||||
|
||||
此时可以套组合总和的回溯法代码,几乎不用改动。
|
||||
|
||||
@ -144,7 +144,7 @@ dp[j] 表示:填满j(包括j)这么大容积的包,有dp[i]种方法
|
||||
|
||||
其实也可以使用二维dp数组来求解本题,dp[i][j]:使用 下标为[0, i]的nums[i]能够凑满j(包括j)这么大容量的包,有dp[i][j]种方法。
|
||||
|
||||
下面我都是统一使用一维数组进行讲解, 二维降为一维(滚动数组),其实就是上一层拷贝下来,这个我在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)也有介绍。
|
||||
下面我都是统一使用一维数组进行讲解, 二维降为一维(滚动数组),其实就是上一层拷贝下来,这个我在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)也有介绍。
|
||||
|
||||
2. 确定递推公式
|
||||
|
||||
@ -179,7 +179,7 @@ dp[j]其他下标对应的数值应该初始化为0,从递归公式也可以
|
||||
|
||||
4. 确定遍历顺序
|
||||
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://mp.weixin.qq.com/s/M4uHxNVKRKm5HPjkNZBnFA)中,我们讲过对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中,我们讲过对于01背包问题一维dp的遍历,nums放在外循环,target在内循环,且内循环倒序。
|
||||
|
||||
|
||||
5. 举例推导dp数组
|
||||
@ -202,7 +202,6 @@ public:
|
||||
for (int i = 0; i < nums.size(); i++) sum += nums[i];
|
||||
if (S > sum) return 0; // 此时没有方案
|
||||
if ((S + sum) % 2 == 1) return 0; // 此时没有方案
|
||||
if (S + sum < 0) return 0; // 以确保bagSize为正数
|
||||
int bagSize = (S + sum) / 2;
|
||||
vector<int> dp(bagSize + 1, 0);
|
||||
dp[0] = 1;
|
||||
@ -222,9 +221,9 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
此时 大家应该不仅想起,我们之前讲过的[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)是不是应该也可以用dp来做啊?
|
||||
此时 大家应该不仅想起,我们之前讲过的[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)是不是应该也可以用dp来做啊?
|
||||
|
||||
是的,如果仅仅是求个数的话,就可以用dp,但[回溯算法:39. 组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)要求的是把所有组合列出来,还是要使用回溯法爆搜的。
|
||||
是的,如果仅仅是求个数的话,就可以用dp,但[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)要求的是把所有组合列出来,还是要使用回溯法爆搜的。
|
||||
|
||||
本题还是有点难度,大家也可以记住,在求装满背包有几种方法的情况下,递推公式一般为:
|
||||
|
||||
@ -312,7 +311,7 @@ Javascript:
|
||||
const findTargetSumWays = (nums, target) => {
|
||||
|
||||
const sum = nums.reduce((a, b) => a+b);
|
||||
|
||||
|
||||
if(target > sum) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
# 496.下一个更大元素 I
|
||||
|
||||
题目链接:https://leetcode-cn.com/problems/next-greater-element-i/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/next-greater-element-i/)
|
||||
|
||||
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
|
||||
|
||||
@ -24,7 +24,7 @@ nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位
|
||||
解释:
|
||||
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
|
||||
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出-1 。
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
* 1 <= nums1.length <= nums2.length <= 1000
|
||||
@ -34,13 +34,13 @@ nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位
|
||||
|
||||
# 思路
|
||||
|
||||
做本题之前,建议先做一下[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)
|
||||
做本题之前,建议先做一下[739. 每日温度](https://programmercarl.com/0739.每日温度.html)
|
||||
|
||||
在[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)中是求每个元素下一个比当前元素大的元素的位置。
|
||||
在[739. 每日温度](https://programmercarl.com/0739.每日温度.html)中是求每个元素下一个比当前元素大的元素的位置。
|
||||
|
||||
本题则是说nums1 是 nums2的子集,找nums1中的元素在nums2中下一个比当前元素大的元素。
|
||||
|
||||
看上去和[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q) 就如出一辙了。
|
||||
看上去和[739. 每日温度](https://programmercarl.com/0739.每日温度.html) 就如出一辙了。
|
||||
|
||||
几乎是一样的,但是这么绕了一下,其实还上升了一点难度。
|
||||
|
||||
@ -60,7 +60,7 @@ nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位
|
||||
|
||||
没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。
|
||||
|
||||
C++中,当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的。我在[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/RSUANESA_tkhKhYe3ZR8Jg)中也做了详细的解释。
|
||||
C++中,当我们要使用集合来解决哈希问题的时候,优先使用unordered_set,因为它的查询和增删效率是最优的。我在[关于哈希表,你该了解这些!](https://programmercarl.com/哈希表理论基础.html)中也做了详细的解释。
|
||||
|
||||
那么预处理代码如下:
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
## 501.二叉搜索树中的众数
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/)
|
||||
|
||||
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
|
||||
|
||||
@ -161,7 +161,7 @@ void searchBST(TreeNode* cur) {
|
||||
|
||||
这就考察对树的操作了。
|
||||
|
||||
在[二叉树:搜索树的最小绝对差](https://mp.weixin.qq.com/s/Hwzml6698uP3qQCC1ctUQQ)中我们就使用了pre指针和cur指针的技巧,这次又用上了。
|
||||
在[二叉树:搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)中我们就使用了pre指针和cur指针的技巧,这次又用上了。
|
||||
|
||||
弄一个指针指向前一个节点,这样每次cur(当前节点)才能和pre(前一个节点)作比较。
|
||||
|
||||
@ -272,8 +272,8 @@ public:
|
||||
|
||||
二叉树前中后序转迭代,传送门:
|
||||
|
||||
* [二叉树:前中后序迭代法](https://mp.weixin.qq.com/s/c_zCrGHIVlBjUH_hJtghCg)
|
||||
* [二叉树:前中后序统一风格的迭代方式](https://mp.weixin.qq.com/s/WKg0Ty1_3SZkztpHubZPRg)
|
||||
* [二叉树:前中后序迭代法](https://programmercarl.com/二叉树的迭代遍历.html)
|
||||
* [二叉树:前中后序统一风格的迭代方式](https://programmercarl.com/二叉树的统一迭代法.html)
|
||||
|
||||
下面我给出其中的一种中序遍历的迭代法,其中间处理逻辑一点都没有变(我从递归法直接粘过来的代码,连注释都没改,哈哈)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
# 503.下一个更大元素II
|
||||
|
||||
链接:https://leetcode-cn.com/problems/next-greater-element-ii/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/next-greater-element-ii/)
|
||||
|
||||
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
|
||||
|
||||
@ -14,13 +14,13 @@
|
||||
|
||||
# 思路
|
||||
|
||||
做本题之前建议先做[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q) 和 [496.下一个更大元素 I](https://mp.weixin.qq.com/s/U0O6XkFOe-RMXthPS16sWQ)。
|
||||
做本题之前建议先做[739. 每日温度](https://programmercarl.com/0739.每日温度.html) 和 [496.下一个更大元素 I](https://programmercarl.com/0496.下一个更大元素I.html)。
|
||||
|
||||
这道题和[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)也几乎如出一辙。
|
||||
这道题和[739. 每日温度](https://programmercarl.com/0739.每日温度.html)也几乎如出一辙。
|
||||
|
||||
不同的时候本题要循环数组了。
|
||||
|
||||
关于单调栈的讲解我在题解[739. 每日温度](https://mp.weixin.qq.com/s/YeQ7eE0-hZpxJfJJziq25Q)中已经详细讲解了。
|
||||
关于单调栈的讲解我在题解[739. 每日温度](https://programmercarl.com/0739.每日温度.html)中已经详细讲解了。
|
||||
|
||||
本篇我侧重与说一说,如何处理循环数组。
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
## 509. 斐波那契数
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/fibonacci-number/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/fibonacci-number/)
|
||||
|
||||
斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
|
||||
F(0) = 0,F(1) = 1
|
||||
@ -29,7 +29,7 @@ F(n) = F(n - 1) + F(n - 2),其中 n > 1
|
||||
输入:4
|
||||
输出:3
|
||||
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
* 0 <= n <= 30
|
||||
@ -47,7 +47,7 @@ F(n) = F(n - 1) + F(n - 2),其中 n > 1
|
||||
|
||||
对于动规,如果没有方法论的话,可能简单题目可以顺手一写就过,难一点就不知道如何下手了。
|
||||
|
||||
所以我总结的动规五部曲,是要用来贯穿整个动态规划系列的,就像之前讲过[二叉树系列的递归三部曲](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ),[回溯法系列的回溯三部曲](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)一样。后面慢慢大家就会体会到,动规五部曲方法的重要性。
|
||||
所以我总结的动规五部曲,是要用来贯穿整个动态规划系列的,就像之前讲过[二叉树系列的递归三部曲](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html),[回溯法系列的回溯三部曲](https://programmercarl.com/回溯算法理论基础.html)一样。后面慢慢大家就会体会到,动规五部曲方法的重要性。
|
||||
|
||||
### 动态规划
|
||||
|
||||
@ -150,14 +150,14 @@ public:
|
||||
* 时间复杂度:O(2^n)
|
||||
* 空间复杂度:O(n) 算上了编程语言中实现递归的系统栈所占空间
|
||||
|
||||
这个递归的时间复杂度大家画一下树形图就知道了,如果不清晰的同学,可以看这篇:[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://mp.weixin.qq.com/s/I6ZXFbw09NR31F5CJR_geQ)
|
||||
这个递归的时间复杂度大家画一下树形图就知道了,如果不清晰的同学,可以看这篇:[通过一道面试题目,讲一讲递归算法的时间复杂度!](https://programmercarl.com/前序/通过一道面试题目,讲一讲递归算法的时间复杂度!.html)
|
||||
|
||||
|
||||
# 总结
|
||||
|
||||
斐波那契数列这道题目是非常基础的题目,我在后面的动态规划的讲解中将会多次提到斐波那契数列!
|
||||
|
||||
这里我严格按照[关于动态规划,你该了解这些!](https://leetcode-cn.com/circle/article/tNuNnM/)中的动规五部曲来分析了这道题目,一些分析步骤可能同学感觉没有必要搞的这么复杂,代码其实上来就可以撸出来。
|
||||
这里我严格按照[关于动态规划,你该了解这些!](https://programmercarl.com/动态规划理论基础.html)中的动规五部曲来分析了这道题目,一些分析步骤可能同学感觉没有必要搞的这么复杂,代码其实上来就可以撸出来。
|
||||
|
||||
但我还是强调一下,简单题是用来掌握方法论的,动规五部曲将在接下来的动态规划讲解中发挥重要作用,敬请期待!
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
# 513.找树左下角的值
|
||||
|
||||
题目地址:[https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/v)
|
||||
[力扣题目链接]([https://leetcode-cn.com/problems/find-bottom-left-tree-value/](https://leetcode-cn.com/problems/find-bottom-left-tree-value/v))
|
||||
|
||||
给定一个二叉树,在树的最后一行找到最左边的值。
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
|
||||
|
||||
如果对二叉树深度和高度还有点疑惑的话,请看:[110.平衡二叉树](https://mp.weixin.qq.com/s/7QeWnxaAB66LjFJOs40XKg)。
|
||||
如果对二叉树深度和高度还有点疑惑的话,请看:[110.平衡二叉树](https://programmercarl.com/0110.平衡二叉树.html)。
|
||||
|
||||
所以要找深度最大的叶子节点。
|
||||
|
||||
@ -170,7 +170,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
如果对回溯部分精简的代码 不理解的话,可以看这篇[257. 二叉树的所有路径](https://mp.weixin.qq.com/s/-x0IL-5eb9W0kZC1-TM0Lw)
|
||||
如果对回溯部分精简的代码 不理解的话,可以看这篇[257. 二叉树的所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)
|
||||
|
||||
|
||||
## 迭代法
|
||||
@ -179,7 +179,7 @@ public:
|
||||
|
||||
只需要记录最后一行第一个节点的数值就可以了。
|
||||
|
||||
如果对层序遍历不了解,看这篇[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA),这篇里也给出了层序遍历的模板,稍作修改就一过刷了这道题了。
|
||||
如果对层序遍历不了解,看这篇[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html),这篇里也给出了层序遍历的模板,稍作修改就一过刷了这道题了。
|
||||
|
||||
代码如下:
|
||||
|
||||
@ -209,9 +209,9 @@ public:
|
||||
|
||||
本题涉及如下几点:
|
||||
|
||||
* 递归求深度的写法,我们在[110.平衡二叉树](https://mp.weixin.qq.com/s/7QeWnxaAB66LjFJOs40XKg)中详细的分析了深度应该怎么求,高度应该怎么求。
|
||||
* 递归中其实隐藏了回溯,在[257. 二叉树的所有路径](https://mp.weixin.qq.com/s/-x0IL-5eb9W0kZC1-TM0Lw)中讲解了究竟哪里使用了回溯,哪里隐藏了回溯。
|
||||
* 层次遍历,在[二叉树:层序遍历登场!](https://mp.weixin.qq.com/s/4-bDKi7SdwfBGRm9FYduiA)深度讲解了二叉树层次遍历。
|
||||
* 递归求深度的写法,我们在[110.平衡二叉树](https://programmercarl.com/0110.平衡二叉树.html)中详细的分析了深度应该怎么求,高度应该怎么求。
|
||||
* 递归中其实隐藏了回溯,在[257. 二叉树的所有路径](https://programmercarl.com/0257.二叉树的所有路径.html)中讲解了究竟哪里使用了回溯,哪里隐藏了回溯。
|
||||
* 层次遍历,在[二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html)深度讲解了二叉树层次遍历。
|
||||
所以本题涉及到的点,我们之前都讲解过,这些知识点需要同学们灵活运用,这样就举一反三了。
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
## 516.最长回文子序列
|
||||
题目链接:https://leetcode-cn.com/problems/longest-palindromic-subsequence/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/longest-palindromic-subsequence/)
|
||||
|
||||
给定一个字符串 s ,找到其中最长的回文子序列,并返回该序列的长度。可以假设 s 的最大长度为 1000 。
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
我们刚刚做过了 [动态规划:回文子串](https://mp.weixin.qq.com/s/2WetyP6IYQ6VotegepVpEw),求的是回文子串,而本题要求的是回文子序列, 要搞清楚这两者之间的区别。
|
||||
我们刚刚做过了 [动态规划:回文子串](https://programmercarl.com/0647.回文子串.html),求的是回文子串,而本题要求的是回文子序列, 要搞清楚这两者之间的区别。
|
||||
|
||||
**回文子串是要连续的,回文子序列可不是连续的!** 回文子串,回文子序列都是动态规划经典题目。
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
## 518. 零钱兑换 II
|
||||
|
||||
链接:https://leetcode-cn.com/problems/coin-change-2/
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/coin-change-2/)
|
||||
|
||||
难度:中等
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
|
||||
这是一道典型的背包问题,一看到钱币数量不限,就知道这是一个完全背包。
|
||||
|
||||
对完全背包还不了解的同学,可以看这篇:[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)
|
||||
对完全背包还不了解的同学,可以看这篇:[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)
|
||||
|
||||
但本题和纯完全背包不一样,**纯完全背包是能否凑成总金额,而本题是要求凑成总金额的个数!**
|
||||
|
||||
@ -78,7 +78,7 @@ dp[j] (考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不
|
||||
|
||||
所以递推公式:dp[j] += dp[j - coins[i]];
|
||||
|
||||
**这个递推公式大家应该不陌生了,我在讲解01背包题目的时候在这篇[动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw)中就讲解了,求装满背包有几种方法,一般公式都是:dp[j] += dp[j - nums[i]];**
|
||||
**这个递推公式大家应该不陌生了,我在讲解01背包题目的时候在这篇[动态规划:目标和!](https://programmercarl.com/0494.目标和.html)中就讲解了,求装满背包有几种方法,一般公式都是:dp[j] += dp[j - nums[i]];**
|
||||
|
||||
3. dp数组如何初始化
|
||||
|
||||
@ -93,7 +93,7 @@ dp[j] (考虑coins[i]的组合总和) 就是所有的dp[j - coins[i]](不
|
||||
本题中我们是外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),还是外层for遍历背包(金钱总额),内层for循环遍历物品(钱币)呢?
|
||||
|
||||
|
||||
我在[动态规划:关于完全背包,你该了解这些!](https://mp.weixin.qq.com/s/akwyxlJ4TLvKcw26KB9uJw)中讲解了完全背包的两个for循环的先后顺序都是可以的。
|
||||
我在[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)中讲解了完全背包的两个for循环的先后顺序都是可以的。
|
||||
|
||||
**但本题就不行了!**
|
||||
|
||||
@ -170,7 +170,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
本题的递推公式,其实我们在[动态规划:目标和!](https://mp.weixin.qq.com/s/2pWmaohX75gwxvBENS-NCw)中就已经讲过了,**而难点在于遍历顺序!**
|
||||
本题的递推公式,其实我们在[动态规划:目标和!](https://programmercarl.com/0494.目标和.html)中就已经讲过了,**而难点在于遍历顺序!**
|
||||
|
||||
在求装满背包有几种方案的时候,认清遍历顺序是非常关键的。
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user