更新图床

This commit is contained in:
programmercarl 2023-03-10 14:02:32 +08:00
parent 2a9b627a90
commit 17cb4b45c7
134 changed files with 1169 additions and 829 deletions

View File

@ -108,7 +108,7 @@ dp[i][j]可以初始化为true么 当然不行,怎能刚开始就全都匹
dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:
![647.回文子串](https://img-blog.csdnimg.cn/20210121171032473.jpg)
![647.回文子串](https://code-thinking-1253855093.file.myqcloud.com/pics/20210121171032473.jpg)
如果这矩阵是从上到下从左到右遍历那么会用到没有计算过的dp[i + 1][j - 1],也就是根据不确定是不是回文的区间[i+1,j-1],来判断了[i,j]是不是回文,那结果一定是不对的。
@ -142,7 +142,7 @@ for (int i = s.size() - 1; i >= 0; i--) { // 注意遍历顺序
举例,输入:"aaa"dp[i][j]状态如下:
![647.回文子串1](https://img-blog.csdnimg.cn/20210121171059951.jpg)
![647.回文子串1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210121171059951.jpg)
**注意因为dp[i][j]的定义所以j一定是大于等于i的那么在填充dp[i][j]的时候一定是只填充右上半部分**。

View File

@ -13,7 +13,7 @@
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
![17.电话号码的字母组合](https://img-blog.csdnimg.cn/2020102916424043.png)
![17.电话号码的字母组合](https://code-thinking-1253855093.file.myqcloud.com/pics/2020102916424043.png)
示例:
* 输入:"23"
@ -66,7 +66,7 @@ const string letterMap[10] = {
例如:输入:"23",抽象为树形结构,如图所示:
![17. 电话号码的字母组合](https://img-blog.csdnimg.cn/20201123200304469.png)
![17. 电话号码的字母组合](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123200304469.png)
图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。

View File

@ -17,7 +17,8 @@
示例 1
![19.删除链表的倒数第N个节点](https://img-blog.csdnimg.cn/20210510085957392.png)
![19.删除链表的倒数第N个节点](https://code-thinking-1253855093.file.myqcloud.com/pics/20210510085957392.png)
输入head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

View File

@ -80,14 +80,17 @@ cd a/b/c/../../
先来分析一下 这里有三种不匹配的情况,
1. 第一种情况,字符串里左方向的括号多余了 ,所以不匹配。
![括号匹配1](https://img-blog.csdnimg.cn/2020080915505387.png)
![括号匹配1](https://code-thinking-1253855093.file.myqcloud.com/pics/2020080915505387.png)
2. 第二种情况,括号没有多余,但是 括号的类型没有匹配上。
![括号匹配2](https://img-blog.csdnimg.cn/20200809155107397.png)
![括号匹配2](https://code-thinking-1253855093.file.myqcloud.com/pics/20200809155107397.png)
3. 第三种情况,字符串里右方向的括号多余了,所以不匹配。
![括号匹配3](https://img-blog.csdnimg.cn/20200809155115779.png)
![括号匹配3](https://code-thinking-1253855093.file.myqcloud.com/pics/20200809155115779.png)
我们的代码只要覆盖了这三种不匹配的情况,就不会出问题,可以看出 动手之前分析好题目的重要性。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -7,6 +8,7 @@
# 35.搜索插入位置
[力扣题目链接](https://leetcode.cn/problems/search-insert-position/)
@ -16,18 +18,22 @@
你可以假设数组中无重复元素。
示例 1:
* 输入: [1,3,5,6], 5
* 输出: 2
示例 2:
示例 2:
* 输入: [1,3,5,6], 2
* 输出: 1
示例 3:
* 输入: [1,3,5,6], 7
* 输出: 4
示例 4:
* 输入: [1,3,5,6], 0
* 输出: 0
@ -37,7 +43,7 @@
这道题目,要在数组中插入目标值,无非是这四种情况。
![35_搜索插入位置3](https://img-blog.csdnimg.cn/20201216232148471.png)
![35_搜索插入位置3](https://code-thinking-1253855093.file.myqcloud.com/pics/20201216232148471.png)
* 目标值在数组所有元素之前
* 目标值等于数组中某一个元素
@ -78,13 +84,14 @@ public:
效率如下:
![35_搜索插入位置](https://img-blog.csdnimg.cn/20201216232127268.png)
![35_搜索插入位置](https://code-thinking-1253855093.file.myqcloud.com/pics/20201216232127268.png)
### 二分法
既然暴力解法的时间复杂度是$O(n)$,就要尝试一下使用二分查找法。
既然暴力解法的时间复杂度是O(n),就要尝试一下使用二分查找法。
![35_搜索插入位置4](https://img-blog.csdnimg.cn/202012162326354.png)
![35_搜索插入位置4](https://code-thinking-1253855093.file.myqcloud.com/pics/202012162326354.png)
大家注意这道题目的前提是数组是有序数组,这也是使用二分查找的基础条件。
@ -94,7 +101,7 @@ public:
大体讲解一下二分法的思路这里来举一个例子例如在这个数组中使用二分法寻找元素为5的位置并返回其下标。
![35_搜索插入位置5](https://img-blog.csdnimg.cn/20201216232659199.png)
![35_搜索插入位置5](https://code-thinking-1253855093.file.myqcloud.com/pics/20201216232659199.png)
二分查找涉及的很多的边界条件,逻辑比较简单,就是写不好。
@ -145,7 +152,7 @@ public:
* 空间复杂度O(1)
效率如下:
![35_搜索插入位置2](https://img-blog.csdnimg.cn/2020121623272877.png)
![35_搜索插入位置2](https://code-thinking-1253855093.file.myqcloud.com/pics/2020121623272877.png)
### 二分法第二种写法
@ -226,6 +233,7 @@ class Solution {
}
}
```
```java
//第二种二分法:左闭右开
public int searchInsert(int[] nums, int target) {
@ -291,6 +299,7 @@ impl Solution {
```
### Python
```python
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
@ -309,6 +318,7 @@ class Solution:
```
### JavaScript
```js
var searchInsert = function (nums, target) {
let l = 0, r = nums.length - 1, ans = nums.length;
@ -383,7 +393,9 @@ func searchInsert(_ nums: [Int], _ target: Int) -> Int {
return right + 1
}
```
### Scala
```scala
object Solution {
def searchInsert(nums: Array[Int], target: Int): Int = {
@ -429,7 +441,9 @@ function searchInsert($nums, $target)
return $r + 1;
}
```
### C
```c
//版本一 [left, right]左闭右闭区间
int searchInsert(int* nums, int numsSize, int target){
@ -455,6 +469,7 @@ int searchInsert(int* nums, int numsSize, int target){
return right + 1;
}
```
```c
//版本二 [left, right]左闭右开区间
int searchInsert(int* nums, int numsSize, int target){

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
如果对回溯法理论还不清楚的同学,可以先看这个视频[视频来了!!带你学透回溯算法(理论篇)](https://mp.weixin.qq.com/s/wDd5azGIYWjbU0fdua_qBg)
# 37. 解数独
@ -14,20 +16,21 @@
编写一个程序,通过填充空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
![解数独](https://img-blog.csdnimg.cn/202011171912586.png)
![解数独](https://code-thinking-1253855093.file.myqcloud.com/pics/202011171912586.png)
一个数独。
![解数独](https://img-blog.csdnimg.cn/20201117191340669.png)
![解数独](https://code-thinking-1253855093.file.myqcloud.com/pics/20201117191340669.png)
答案被标成红色。
提示:
* 给定的数独序列只包含数字 1-9 和字符 '.' 。
* 你可以假设给定的数独只有唯一解。
* 给定数独永远是 9x9 形式的。
@ -54,7 +57,7 @@
因为这个树形结构太大了,我抽取一部分,如图所示:
![37.解数独](https://img-blog.csdnimg.cn/2020111720451790.png)
![37.解数独](https://code-thinking-1253855093.file.myqcloud.com/pics/2020111720451790-20230310131816104.png)
### 回溯三部曲
@ -85,7 +88,7 @@ bool backtracking(vector<vector<char>>& board)
* 递归单层搜索逻辑
![37.解数独](https://img-blog.csdnimg.cn/2020111720451790.png)
![37.解数独](https://code-thinking-1253855093.file.myqcloud.com/pics/2020111720451790-20230310131822254.png)
在树形图中可以看出我们需要的是一个二维的递归也就是两个for循环嵌套着递归
@ -224,6 +227,7 @@ public:
### Java
```java
class Solution {
public void solveSudoku(char[][] board) {
@ -292,6 +296,7 @@ class Solution {
```
### Python
```python
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
@ -393,6 +398,7 @@ func isvalid(row, col int, k byte, board [][]byte) bool {
### Javascript
```Javascript
var solveSudoku = function(board) {
function isValid(row, col, val, board) {
@ -660,6 +666,7 @@ func solveSudoku(_ board: inout [[Character]]) {
### Scala
详细写法:
```scala
object Solution {
@ -717,6 +724,7 @@ object Solution {
```
遵循Scala至简原则写法
```scala
object Solution {

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,20 +6,22 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 39. 组合总和
[力扣题目链接](https://leetcode.cn/problems/combination-sum/)
给定一个无重复元素的数组 candidates 和一个目标数 target 找出 candidates 中所有可以使数字和为 target 的组合。
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
candidates 中的数字可以无限制重复被选取。
说明:
* 所有数字(包括 target都是正整数。
* 解集不能包含重复的组合。 
* 所有数字(包括 target都是正整数。
* 解集不能包含重复的组合。
示例 1
* 输入candidates = [2,3,6,7], target = 7,
* 所求解集为:
[
@ -26,13 +29,14 @@ candidates 中的数字可以无限制重复被选取。
[2,2,3]
]
示例 2
示例 2
* 输入candidates = [2,3,5], target = 8,
* 所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
[2,2,2,2],
[2,3,3],
[3,5]
]
# 算法公开课
@ -48,7 +52,7 @@ candidates 中的数字可以无限制重复被选取。
本题搜索的过程抽象成树形结构如下:
![39.组合总和](https://img-blog.csdnimg.cn/20201223170730367.png)
![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223170730367.png)
注意图中叶子节点的返回条件因为本题没有组合数量要求仅仅是总和的限制所以递归没有层数的限制只要选取的元素总和超过target就返回
而在[77.组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html) 中都可以知道要递归K层因为要取k个元素的组合。
@ -83,7 +87,7 @@ void backtracking(vector<int>& candidates, int target, int sum, int startIndex)
在如下树形结构中:
![39.组合总和](https://img-blog.csdnimg.cn/20201223170730367.png)
![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223170730367-20230310135337214.png)
从叶子节点可以清晰看到终止只有两种情况sum大于target和sum等于target。
@ -156,7 +160,7 @@ public:
在这个树形结构中:
![39.组合总和](https://img-blog.csdnimg.cn/20201223170730367.png)
![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223170730367-20230310135342472.png)
以及上面的版本一的代码大家可以看到对于sum已经大于target的情况其实是依然进入了下一层递归只是下一层递归结束判断的时候会判断sum > target的话就返回。
@ -169,7 +173,7 @@ public:
如图:
![39.组合总和1](https://img-blog.csdnimg.cn/20201223170809182.png)
![39.组合总和1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223170809182.png)
for循环剪枝代码如下
@ -236,6 +240,7 @@ public:
## Java
```Java
// 剪枝优化
class Solution {
@ -265,7 +270,9 @@ class Solution {
```
## Python
**回溯**
```python
class Solution:
def __init__(self):
@ -297,7 +304,9 @@ class Solution:
sum_ -= candidates[i] # 回溯
self.path.pop() # 回溯
```
**剪枝回溯**
```python
class Solution:
def __init__(self):
@ -334,6 +343,7 @@ class Solution:
```
## Go
主要在于递归中传递下一个数字
```go

View File

@ -82,7 +82,7 @@ candidates 中的每个数字在每个组合中只能使用一次。
选择过程树形结构如图所示:
![40.组合总和II](https://img-blog.csdnimg.cn/20201123202736384.png)
![40.组合总和II](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000918.png)
可以看到图中,每个节点相对于 [39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)我多加了used数组这个used数组下面会重点介绍。
@ -132,7 +132,7 @@ if (sum == target) {
这块比较抽象,如图:
![40.组合总和II1](https://img-blog.csdnimg.cn/20201123202817973.png)
![40.组合总和II1](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000954.png)
我在图中将used的变化用橘黄色标注上可以看出在candidates[i] == candidates[i - 1]相同的情况下:

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 这个图就是大厂面试经典题目,接雨水! 最常青藤的一道题,面试官百出不厌!
# 42. 接雨水
@ -32,6 +34,7 @@
接雨水问题在面试中还是常见题目的,有必要好好讲一讲。
本文深度讲解如下三种方法:
* 双指针法
* 动态规划
* 单调栈
@ -43,10 +46,10 @@
首先要明确,要按照行来计算,还是按照列来计算。
按照行来计算如图:
![42.接雨水2](https://img-blog.csdnimg.cn/20210402091118927.png)
![42.接雨水2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210402091118927.png)
按照列来计算如图:
![42.接雨水1](https://img-blog.csdnimg.cn/20210402091208445.png)
![42.接雨水1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210402091208445.png)
一些同学在实现的时候,很容易一会按照行来计算一会按照列来计算,这样就会越写越乱。
@ -58,7 +61,7 @@
这句话可以有点绕来举一个理解例如求列4的雨水高度如图
![42.接雨水3](https://img-blog.csdnimg.cn/20210223092732301.png)
![42.接雨水3](https://code-thinking-1253855093.file.myqcloud.com/pics/20210223092732301.png)
列4 左侧最高的柱子是列3高度为2以下用lHeight表示
@ -197,7 +200,7 @@ public:
1. 首先单调栈是按照行方向来计算雨水,如图:
![42.接雨水2](https://img-blog.csdnimg.cn/20210223092629946.png)
![42.接雨水2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210223092629946.png)
知道这一点,后面的就可以理解了。
@ -211,7 +214,7 @@ public:
如图:
![42.接雨水4](https://img-blog.csdnimg.cn/2021022309321229.png)
![42.接雨水4](https://code-thinking-1253855093.file.myqcloud.com/pics/2021022309321229.png)
关于单调栈的顺序给大家一个总结: [739. 每日温度](https://programmercarl.com/0739.每日温度.html) 中求一个元素右边第一个更大元素,单调栈就是递增的,[84.柱状图中最大的矩形](https://programmercarl.com/0084.柱状图中最大的矩形.html)求一个元素右边第一个更小元素,单调栈就是递减的。
@ -225,7 +228,7 @@ public:
如图所示:
![42.接雨水5](https://img-blog.csdnimg.cn/20210223094619398.png)
![42.接雨水5](https://code-thinking-1253855093.file.myqcloud.com/pics/20210223094619398.png)
4. 栈里要保存什么数值
@ -280,7 +283,7 @@ if (height[i] == height[st.top()]) { // 例如 5 5 1 7 这种情况
如果当前遍历的元素(柱子)高度大于栈顶元素的高度,此时就出现凹槽了,如图所示:
![42.接雨水4](https://img-blog.csdnimg.cn/2021022309321229.png)
![42.接雨水4](https://code-thinking-1253855093.file.myqcloud.com/pics/2021022309321229-20230310123027977.png)
取栈顶元素将栈顶元素弹出这个就是凹槽的底部也就是中间位置下标记为mid对应的高度为height[mid]就是图中的高度1
@ -378,6 +381,7 @@ public:
### Java:
暴力解法:
```java
class Solution {
public int trap(int[] height) {
@ -404,6 +408,7 @@ class Solution {
```
双指针:
```java
class Solution {
public int trap(int[] height) {
@ -432,6 +437,7 @@ class Solution {
```
单调栈法
```java
class Solution {
public int trap(int[] height){
@ -481,6 +487,7 @@ class Solution {
### Python:
暴力解法:
```Python
class Solution:
def trap(self, height: List[int]) -> int:
@ -502,6 +509,7 @@ class Solution:
```
双指针:
```python
class Solution:
def trap(self, height: List[int]) -> int:
@ -520,7 +528,9 @@ class Solution:
result += summ
return result
```
单调栈
```Python
class Solution:
def trap(self, height: List[int]) -> int:
@ -652,6 +662,7 @@ func min(a,b int)int{
```
单调栈解法
```go
func trap(height []int) int {
if len(height) <= 2 {

View File

@ -46,7 +46,8 @@
如图:
![45.跳跃游戏II](https://img-blog.csdnimg.cn/20201201232309103.png)
![45.跳跃游戏II](https://code-thinking-1253855093.file.myqcloud.com/pics/20201201232309103.png)
**图中覆盖范围的意义在于,只要红色的区域,最多两步一定可以到!(不用管具体怎么跳,反正一定可以跳到)**
@ -96,11 +97,11 @@ public:
因为当移动下标指向nums.size - 2时
* 如果移动下标等于当前覆盖最大距离下标, 需要再走一步即ans++),因为最后一步一定是可以到的终点。(题目假设总是可以到达数组的最后一个位置),如图:
![45.跳跃游戏II2](https://img-blog.csdnimg.cn/20201201232445286.png)
![45.跳跃游戏II2](https://code-thinking-1253855093.file.myqcloud.com/pics/20201201232445286.png)
* 如果移动下标不等于当前覆盖最大距离下标,说明当前覆盖最远距离就可以直接达到终点了,不需要再走一步。如图:
![45.跳跃游戏II1](https://img-blog.csdnimg.cn/20201201232338693.png)
![45.跳跃游戏II1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201201232338693.png)
代码如下:

View File

@ -66,7 +66,7 @@ void backtracking (vector<int>& nums, vector<bool>& used)
* 递归终止条件
![46.全排列](https://img-blog.csdnimg.cn/20201209174225145.png)
![46.全排列](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209174225145.png)
可以看出叶子节点,就是收割结果的地方。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 47.全排列 II
[力扣题目链接](https://leetcode.cn/problems/permutations-ii/)
@ -12,6 +14,7 @@
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1
* 输入nums = [1,1,2]
* 输出:
[[1,1,2],
@ -19,10 +22,12 @@
[2,1,1]]
示例 2
* 输入nums = [1,2,3]
* 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:
* 1 <= nums.length <= 8
* -10 <= nums[i] <= 10
@ -45,7 +50,7 @@
我以示例中的 [1,1,2]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:
![47.全排列II1](https://img-blog.csdnimg.cn/20201124201331223.png)
![47.全排列II1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124201331223.png)
图中我们对同一树层前一位也就是nums[i-1])如果使用过,那么就进行去重。
@ -123,23 +128,26 @@ if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) {
树层上去重(used[i - 1] == false),的树形结构如下:
![47.全排列II2](https://img-blog.csdnimg.cn/20201124201406192.png)
![47.全排列II2](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124201406192.png)
树枝上去重used[i - 1] == true的树型结构如下
![47.全排列II3](https://img-blog.csdnimg.cn/20201124201431571.png)
![47.全排列II3](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124201431571.png)
大家应该很清晰的看到,树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。
## 总结
这道题其实还是用了我们之前讲过的去重思路,但有意思的是,去重的代码中,这么写:
```cpp
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}
```
和这么写:
```cpp
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == true) {
continue;
@ -264,7 +272,6 @@ func dfs(nums []int, cur int) {
### Javascript
```javascript
var permuteUnique = function (nums) {
nums.sort((a, b) => {
return a - b
@ -392,6 +399,7 @@ impl Solution {
```
### C
```c
//临时数组
int *path;

View File

@ -47,7 +47,7 @@ n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,
下面我用一个 3 * 3 的棋盘,将搜索过程抽象为一棵树,如图:
![51.N皇后](https://img-blog.csdnimg.cn/20210130182532303.jpg)
![51.N皇后](https://code-thinking-1253855093.file.myqcloud.com/pics/20210130182532303.jpg)
从图中,可以看出,二维矩阵中矩阵的高就是这棵树的高度,矩阵的宽就是树形结构中每一个节点的宽度。
@ -87,7 +87,7 @@ void backtracking(int n, int row, vector<string>& chessboard) {
* 递归终止条件
在如下树形结构中:
![51.N皇后](https://img-blog.csdnimg.cn/20210130182532303.jpg)
![51.N皇后](https://code-thinking-1253855093.file.myqcloud.com/pics/20210130182532303-20230310122134167.jpg)
可以看出,当递归到棋盘最底层(也就是叶子节点)的时候,就可以收集结果并返回了。

View File

@ -13,7 +13,9 @@
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
![51n皇后](https://img-blog.csdnimg.cn/20200821152118456.png)
![51n皇后](https://code-thinking-1253855093.file.myqcloud.com/pics/20200821152118456.png)
给定一个整数 n返回 n 皇后不同的解决方案的数量。

View File

@ -51,7 +51,7 @@ dp[0]应该是多少呢?
5. 举例推导dp数组
以示例一为例输入nums = [-2,1,-3,4,-1,2,1,-5,4]对应的dp状态如下
![53.最大子序和(动态规划)](https://img-blog.csdnimg.cn/20210303104129101.png)
![53.最大子序和(动态规划)](https://code-thinking-1253855093.file.myqcloud.com/pics/20210303104129101.png)
**注意最后的结果可不是dp[nums.size() - 1]** 而是dp[6]。

View File

@ -37,7 +37,8 @@
由外向内一圈一圈这么画下去,如下所示:
![螺旋矩阵](https://img-blog.csdnimg.cn/2020121623550681.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20220922102236.png)
这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

View File

@ -46,7 +46,8 @@
如图:
![55.跳跃游戏](https://img-blog.csdnimg.cn/20201124154758229.png)
![55.跳跃游戏](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124154758229-20230310135019977.png)
i每次移动只能在cover的范围内移动每移动一个元素cover得到该元素数值新的覆盖范围的补充让i继续移动下去。

View File

@ -37,7 +37,7 @@
这么说有点抽象,看图:(**注意图中区间都是按照左边界排序之后了**
![56.合并区间](https://img-blog.csdnimg.cn/20201223200632791.png)
![56.合并区间](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223200632791.png)
知道如何判断重复之后,剩下的就是合并了,如何去模拟合并区间呢?

View File

@ -1,14 +1,16 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 62.不同路径
[力扣题目链接](https://leetcode.cn/problems/unique-paths/)
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
@ -16,30 +18,35 @@
示例 1
![](https://img-blog.csdnimg.cn/20210110174033215.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210110174033215.png)
* 输入m = 3, n = 7
* 输出28
示例 2
* 输入m = 2, n = 3
* 输出3
解释: 从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 3
* 输入m = 7, n = 3
* 输出28
示例 4
* 输入m = 3, n = 3
* 输出6
提示:
* 1 <= m, n <= 100
* 题目数据保证答案小于等于 2 * 10^9
@ -57,7 +64,7 @@
如图举例:
![62.不同路径](https://img-blog.csdnimg.cn/20201209113602700.png)
![62.不同路径](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209113602700.png)
此时问题就可以转化为求二叉树叶子节点的个数,代码如下:
@ -126,7 +133,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
如图所示:
![62.不同路径1](https://img-blog.csdnimg.cn/20201209113631392.png)
![62.不同路径1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209113631392.png)
以上动规五部曲分析完毕C++代码如下:
@ -175,7 +182,7 @@ public:
在这个图中可以看出一共mn的话无论怎么走走到终点都需要 m + n - 2 步。
![62.不同路径](https://img-blog.csdnimg.cn/20201209113602700.png)
![62.不同路径](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209113602700-20230310120944078.png)
在这m + n - 2 步中,一定有 m - 1 步是要向下走的,不用管什么时候向下走。
@ -185,7 +192,7 @@ public:
那么答案,如图所示:
![62.不同路径2](https://img-blog.csdnimg.cn/20201209113725324.png)
![62.不同路径2](https://code-thinking-1253855093.file.myqcloud.com/pics/20201209113725324.png)
**求组合的时候要防止两个int相乘溢出** 所以不能把算式的分子都算出来,分母都算出来再做除法。
@ -246,6 +253,7 @@ public:
### Java
```java
/**
* 1. 确定dp数组下标含义 dp[i][j] 到每一个坐标可能的路径种类
@ -279,6 +287,7 @@ public:
```
### Python
```python
class Solution: # 动态规划
def uniquePaths(self, m: int, n: int) -> int:
@ -290,6 +299,7 @@ class Solution: # 动态规划
```
### Go
```Go
func uniquePaths(m int, n int) int {
dp := make([][]int, m)
@ -310,6 +320,7 @@ func uniquePaths(m int, n int) int {
```
### Javascript
```Javascript
var uniquePaths = function(m, n) {
const dp = Array(m).fill().map(item => Array(n))
@ -330,7 +341,9 @@ var uniquePaths = function(m, n) {
return dp[m - 1][n - 1]
};
```
>版本二直接将dp数值值初始化为1
```javascript
/**
* @param {number} m
@ -440,6 +453,7 @@ int uniquePaths(int m, int n){
```
滚动数组解法:
```c
int uniquePaths(int m, int n){
int i, j;

View File

@ -1,9 +1,11 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 63. 不同路径 II
[力扣题目链接](https://leetcode.cn/problems/unique-paths-ii/)
@ -14,13 +16,13 @@
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
![](https://img-blog.csdnimg.cn/20210111204901338.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210111204901338.png)
网格中的障碍物和空位置分别用 1 和 0 来表示。
示例 1
![](https://img-blog.csdnimg.cn/20210111204939971.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210111204939971.png)
* 输入obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
* 输出2
@ -32,14 +34,15 @@
示例 2
![](https://img-blog.csdnimg.cn/20210111205857918.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210111205857918.png)
* 输入obstacleGrid = [[0,1],[0,0]]
* 输出1
提示:
* m == obstacleGrid.length
* n == obstacleGrid[i].length
* m == obstacleGrid.length
* n == obstacleGrid[i].length
* 1 <= m, n <= 100
* obstacleGrid[i][j] 为 0 或 1
@ -92,7 +95,7 @@ for (int j = 0; j < n; j++) dp[0][j] = 1;
如图:
![63.不同路径II](https://img-blog.csdnimg.cn/20210104114513928.png)
![63.不同路径II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210104114513928.png)
下标(0, j)的初始化情况同理。
@ -126,13 +129,13 @@ for (int i = 1; i < m; i++) {
拿示例1来举例如题
![63.不同路径II1](https://img-blog.csdnimg.cn/20210104114548983.png)
![63.不同路径II1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210104114548983.png)
对应的dp table 如图:
![63.不同路径II2](https://img-blog.csdnimg.cn/20210104114610256.png)
![63.不同路径II2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210104114610256.png)
如果这个图看不同,建议在理解一下递归公式,然后照着文章中说的遍历顺序,自己推导一下
如果这个图看不同,建议在理解一下递归公式,然后照着文章中说的遍历顺序,自己推导一下!
动规五部分分析完毕对应C++代码如下:
@ -163,6 +166,7 @@ public:
同样我们给出空间优化版本:
```CPP
class Solution {
public:
@ -369,6 +373,7 @@ func uniquePathsWithObstacles(obstacleGrid [][]int) int {
```
### Javascript
```Javascript
var uniquePathsWithObstacles = function(obstacleGrid) {
const m = obstacleGrid.length
@ -545,6 +550,7 @@ int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize, int* obst
```
空间优化版本:
```c
int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize, int* obstacleGridColSize){
int m = obstacleGridSize;

View File

@ -102,7 +102,8 @@ dp[i] 爬到第i层楼梯有dp[i]种方法
举例当n为5的时候dp tabledp数组应该是这样的
![70.爬楼梯](https://img-blog.csdnimg.cn/20210105202546299.png)
![70.爬楼梯](https://code-thinking-1253855093.file.myqcloud.com/pics/20210105202546299.png)
如果代码出问题了就把dp table 打印出来,看看究竟是不是和自己推导的一样。

View File

@ -169,7 +169,7 @@ for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
可以看出dp[i][j]是依赖左方,上方和左上方元素的,如图:
![72.编辑距离](https://img-blog.csdnimg.cn/20210114162113131.jpg)
![72.编辑距离](https://code-thinking-1253855093.file.myqcloud.com/pics/20210114162113131.jpg)
所以在dp矩阵中一定是从左到右从上到下去遍历。
@ -193,7 +193,7 @@ for (int i = 1; i <= word1.size(); i++) {
以示例1为例输入`word1 = "horse", word2 = "ros"`为例dp矩阵状态图如下
![72.编辑距离1](https://img-blog.csdnimg.cn/20210114162132300.jpg)
![72.编辑距离1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210114162132300.jpg)
以上动规五部分析完毕C++代码如下:

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -7,6 +8,7 @@
# 第77题. 组合
[力扣题目链接](https://leetcode.cn/problems/combinations/ )
@ -14,7 +16,7 @@
给定两个整数 n 和 k返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输入: n = 4, k = 2
输出:
[
[2,4],
@ -39,6 +41,7 @@
直接的解法当然是使用for循环例如示例中k为2很容易想到 用两个for循环这样就可以输出 和示例中一样的结果。
代码如下:
```CPP
int n = 4;
for (int i = 1; i <= n; i++) {
@ -86,7 +89,7 @@ for (int i = 1; i <= n; i++) {
那么我把组合问题抽象为如下树形结构:
![77.组合](https://img-blog.csdnimg.cn/20201123195223940.png)
![77.组合](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123195223940.png)
可以看出这棵树,一开始集合是 1234 从左向右取数,取过的数,不再重复取。
@ -130,7 +133,7 @@ vector<int> path; // 用来存放符合条件结果
从下图中红线部分可以看出,在集合[1,2,3,4]取1之后下一层递归就要在[2,3,4]中取数了,那么下一层递归如何知道从[2,3,4]中取数呢靠的就是startIndex。
![77.组合2](https://img-blog.csdnimg.cn/20201123195328976.png)
![77.组合2](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123195328976.png)
所以需要startIndex来记录下一层递归搜索的起始位置。
@ -150,7 +153,7 @@ path这个数组的大小如果达到k说明我们找到了一个子集大小
如图红色部分:
![77.组合3](https://img-blog.csdnimg.cn/20201123195407907.png)
![77.组合3](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123195407907.png)
此时用result二维数组把path保存起来并终止本层递归。
@ -167,7 +170,7 @@ if (path.size() == k) {
回溯法的搜索过程就是一个树型结构的遍历过程在如下图中可以看出for循环用来横向遍历递归的过程是纵向遍历。
![77.组合1](https://img-blog.csdnimg.cn/20201123195242899.png)
![77.组合1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123195242899.png)
如此我们才遍历完图中的这棵树。
@ -219,6 +222,7 @@ public:
还记得我们在[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中给出的回溯法模板么?
如下:
```
void backtracking(参数) {
if (终止条件) {
@ -266,7 +270,7 @@ for (int i = startIndex; i <= n; i++) {
这么说有点抽象,如图所示:
![77.组合4](https://img-blog.csdnimg.cn/20210130194335207.png)
![77.组合4](https://code-thinking-1253855093.file.myqcloud.com/pics/20210130194335207-20230310134409532.png)
图中每一个节点图中为矩形就代表本层的一个for循环那么每一层的for循环从第二个数开始遍历的话都没有意义都是无效遍历。
@ -275,6 +279,7 @@ for (int i = startIndex; i <= n; i++) {
**如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了**。
注意代码中i就是for循环里选择的起始位置。
```
for (int i = startIndex; i <= n; i++) {
```
@ -342,6 +347,7 @@ public:
### Java
```java
class Solution {
List<List<Integer>> result = new ArrayList<>();
@ -417,6 +423,7 @@ class Solution:
```
剪枝:
```python
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
@ -435,6 +442,7 @@ class Solution:
```
### Go
```Go
var (
path []int
@ -468,6 +476,7 @@ func dfs(n int, k int, start int) {
### javascript
剪枝:
```javascript
let result = []
let path = []
@ -536,6 +545,7 @@ impl Solution {
```
剪枝
```Rust
impl Solution {
fn backtracking(result: &mut Vec<Vec<i32>>, path: &mut Vec<i32>, n: i32, k: i32, start_index: i32) {
@ -561,6 +571,7 @@ impl Solution {
```
### C
```c
int* path;
int pathTop;
@ -615,6 +626,7 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
```
剪枝:
```c
int* path;
int pathTop;
@ -701,6 +713,7 @@ func combine(_ n: Int, _ k: Int) -> [[Int]] {
### Scala
暴力:
```scala
object Solution {
import scala.collection.mutable // 导包

View File

@ -66,7 +66,7 @@ for (int i = startIndex; i <= n; i++) {
这么说有点抽象,如图所示:
![77.组合4](https://img-blog.csdnimg.cn/20210130194335207.png)
![77.组合4](https://code-thinking-1253855093.file.myqcloud.com/pics/20210130194335207.png)
图中每一个节点图中为矩形就代表本层的一个for循环那么每一层的for循环从第二个数开始遍历的话都没有意义都是无效遍历。

View File

@ -48,7 +48,7 @@
以示例中nums = [1,2,3]为例把求子集抽象为树型结构,如下:
![78.子集](https://img-blog.csdnimg.cn/202011232041348.png)
![78.子集](https://code-thinking.cdn.bcebos.com/pics/78.%E5%AD%90%E9%9B%86.png)
从图中红线部分,可以看出**遍历这个树的时候,把所有节点都记录下来,就是要求的子集集合**。
@ -72,7 +72,7 @@ void backtracking(vector<int>& nums, int startIndex) {
从图中可以看出:
![78.子集](https://img-blog.csdnimg.cn/202011232041348.png)
![78.子集](https://code-thinking.cdn.bcebos.com/pics/78.%E5%AD%90%E9%9B%86.png)
剩余集合为空的时候,就是叶子节点。

View File

@ -42,7 +42,7 @@
用示例中的[1, 2, 2] 来举例,如图所示: **注意去重需要先对集合排序**
![90.子集II](https://img-blog.csdnimg.cn/20201124195411977.png)
![90.子集II](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124195411977.png)
从图中可以看出同一树层上重复取2 就要过滤掉同一树枝上就可以重复取2因为同一树枝上元素的集合才是唯一子集

View File

@ -59,7 +59,8 @@
切割问题可以抽象为树型结构,如图:
![93.复原IP地址](https://img-blog.csdnimg.cn/20201123203735933.png)
![93.复原IP地址](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123203735933.png)
## 回溯三部曲
@ -110,7 +111,8 @@ if (pointNum == 3) { // 逗点数量为3时分隔结束
如果不合法就结束本层循环,如图中剪掉的分支:
![93.复原IP地址](https://img-blog.csdnimg.cn/20201123203735933.png)
![93.复原IP地址](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123203735933-20230310132314109.png)
然后就是递归和回溯的过程:

View File

@ -1,9 +1,11 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 96.不同的二叉搜索树
[力扣题目链接](https://leetcode.cn/problems/unique-binary-search-trees/)
@ -12,7 +14,7 @@
示例:
![](https://img-blog.csdnimg.cn/20210113161941835.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210113161941835.png)
# 算法公开课
@ -27,11 +29,11 @@
了解了二叉搜索树之后,我们应该先举几个例子,画画图,看看有没有什么规律,如图:
![96.不同的二叉搜索树](https://img-blog.csdnimg.cn/20210107093106367.png)
![96.不同的二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210107093106367.png)
n为1的时候有一棵树n为2有两棵树这个是很直观的。
![96.不同的二叉搜索树1](https://img-blog.csdnimg.cn/20210107093129889.png)
![96.不同的二叉搜索树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210107093129889.png)
来看看n为3的时候有哪几种情况。
@ -65,7 +67,7 @@ dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索
如图所示:
![96.不同的二叉搜索树2](https://img-blog.csdnimg.cn/20210107093226241.png)
![96.不同的二叉搜索树2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210107093226241.png)
此时我们已经找到递推关系了,那么可以用动规五部曲再系统分析一遍。
@ -118,7 +120,7 @@ for (int i = 1; i <= n; i++) {
n为5时候的dp数组状态如图
![96.不同的二叉搜索树3](https://img-blog.csdnimg.cn/20210107093253987.png)
![96.不同的二叉搜索树3](https://code-thinking-1253855093.file.myqcloud.com/pics/20210107093253987.png)
当然如果自己画图举例的话基本举例到n为3就可以了n为4的时候画图已经比较麻烦了。
@ -169,6 +171,7 @@ public:
### Java
```Java
class Solution {
public int numTrees(int n) {
@ -190,6 +193,7 @@ class Solution {
```
### Python
```python
class Solution:
def numTrees(self, n: int) -> int:
@ -202,6 +206,7 @@ class Solution:
```
### Go
```Go
func numTrees(n int)int{
dp := make([]int, n+1)
@ -216,6 +221,7 @@ func numTrees(n int)int{
```
### Javascript
```Javascript
const numTrees =(n) => {
let dp = new Array(n+1).fill(0);

View File

@ -18,7 +18,7 @@
* 节点的右子树只包含大于当前节点的数。
* 所有左子树和右子树自身必须也是二叉搜索树。
![98.验证二叉搜索树](https://img-blog.csdnimg.cn/20210203144334501.png)
![98.验证二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000750.png)
# 视频讲解
@ -104,7 +104,7 @@ if (root->val > root->left->val && root->val < root->right->val) {
例如: [10,5,15,null,null,6,20] 这个case
![二叉搜索树](https://img-blog.csdnimg.cn/20200812191501419.png)
![二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000824.png)
节点10大于左节点5小于右节点15但右子树里出现了一个6 这就不符合了!

View File

@ -11,7 +11,7 @@
给定一个二叉树,检查它是否是镜像对称的。
![101. 对称二叉树](https://img-blog.csdnimg.cn/20210203144607387.png)
![101. 对称二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203144607387.png)
# 思路
@ -25,7 +25,7 @@
比较的是两个子树的里侧和外侧的元素是否相等。如图所示:
![101. 对称二叉树1](https://img-blog.csdnimg.cn/20210203144624414.png)
![101. 对称二叉树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203144624414.png)
那么遍历的顺序应该是什么样的呢?

View File

@ -1,9 +1,11 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 二叉树层序遍历登场!
《代码随想录》算法视频公开课:[讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode102.二叉树的层序遍历](https://www.bilibili.com/video/BV1GY4y1u7b2),相信结合视频在看本篇题解,更有助于大家对本题的理解。
@ -35,7 +37,7 @@
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
![102.二叉树的层序遍历](https://img-blog.csdnimg.cn/20210203144842988.png)
![102.二叉树的层序遍历](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203144842988.png)
思路:
@ -87,6 +89,7 @@ public:
}
};
```
```CPP
# 递归法
class Solution {
@ -168,7 +171,6 @@ python3代码
```python
class Solution:
"""二叉树层序遍历迭代解法"""
@ -194,6 +196,7 @@ class Solution:
return results
```
```python
# 递归法
class Solution:
@ -387,7 +390,9 @@ func levelOrder(_ root: TreeNode?) -> [[Int]] {
return result
}
```
Scala:
```scala
// 102.二叉树的层序遍历
object Solution {
@ -455,7 +460,7 @@ impl Solution {
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
![107.二叉树的层次遍历II](https://img-blog.csdnimg.cn/20210203151058308.png)
![107.二叉树的层次遍历II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151058308.png)
思路:
@ -488,6 +493,7 @@ public:
}
};
```
python代码
```python
@ -719,6 +725,7 @@ func levelOrderBottom(_ root: TreeNode?) -> [[Int]] {
Scala:
```scala
// 107.二叉树的层次遍历II
object Solution {
@ -781,7 +788,7 @@ impl Solution {
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
![199.二叉树的右视图](https://img-blog.csdnimg.cn/20210203151307377.png)
![199.二叉树的右视图](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151307377.png)
思路:
@ -810,6 +817,7 @@ public:
}
};
```
python代码
```python
@ -892,7 +900,6 @@ public class N0199 {
go:
```GO
/**
199. 二叉树的右视图
*/
@ -997,6 +1004,7 @@ func rightSideView(_ root: TreeNode?) -> [Int] {
```
Scala:
```scala
// 199.二叉树的右视图
object Solution {
@ -1060,7 +1068,7 @@ impl Solution {
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
![637.二叉树的层平均值](https://img-blog.csdnimg.cn/20210203151350500.png)
![637.二叉树的层平均值](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151350500.png)
思路:
@ -1125,7 +1133,6 @@ class Solution:
java:
```java
// 637. 二叉树的层平均值
public class N0637 {
@ -1280,7 +1287,9 @@ func averageOfLevels(_ root: TreeNode?) -> [Double] {
return result
}
```
Scala:
```scala
// 637.二叉树的层平均值
object Solution {
@ -1346,7 +1355,7 @@ impl Solution {
例如,给定一个 3叉树 :
![429. N叉树的层序遍历](https://img-blog.csdnimg.cn/20210203151439168.png)
![429. N叉树的层序遍历](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151439168.png)
返回其层序遍历:
@ -1432,10 +1441,10 @@ class Solution:
traversal(root,0)
return result
```
java:
```java
// 429. N 叉树的层序遍历
public class N0429 {
/**
@ -1602,6 +1611,7 @@ func levelOrder(_ root: Node?) -> [[Int]] {
```
Scala:
```scala
// 429.N叉树的层序遍历
object Solution {
@ -1683,7 +1693,7 @@ impl Solution {
您需要在二叉树的每一行中找到最大的值。
![515.在每个树行中找最大值](https://img-blog.csdnimg.cn/20210203151532153.png)
![515.在每个树行中找最大值](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203151532153.png)
思路:
@ -1714,6 +1724,7 @@ public:
}
};
```
python代码
```python
@ -1734,6 +1745,7 @@ class Solution:
out_list.append(max(in_list))
return out_list
```
java代码
```java
@ -1884,6 +1896,7 @@ func largestValues(_ root: TreeNode?) -> [Int] {
```
Scala:
```scala
// 515.在每个树行中找最大值
object Solution {
@ -1959,9 +1972,9 @@ struct Node {
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
![116.填充每个节点的下一个右侧节点指针](https://img-blog.csdnimg.cn/20210203152044855.jpg)
![116.填充每个节点的下一个右侧节点指针](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203152044855.jpg)
思路:
@ -2067,6 +2080,7 @@ class Solution:
first = first.left # 从本层扩展到下一层
return root
```
go:
```GO
@ -2108,8 +2122,8 @@ func connect(root *Node) *Node {
```
JavaScript:
```javascript
```javascript
/**
* // Definition for a Node.
* function Node(val, left, right, next) {
@ -2142,6 +2156,7 @@ var connect = function(root) {
};
```
TypeScript:
```typescript
@ -2200,6 +2215,7 @@ func connect(_ root: Node?) -> Node? {
```
Scala:
```scala
// 116.填充每个节点的下一个右侧节点指针
object Solution {
@ -2228,6 +2244,7 @@ object Solution {
}
}
```
# 117.填充每个节点的下一个右侧节点指针II
[力扣题目链接](https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/)
@ -2307,6 +2324,7 @@ class Solution {
}
}
```
python代码
```python
@ -2329,6 +2347,7 @@ class Solution:
return root
```
go:
```GO
@ -2369,6 +2388,7 @@ func connect(root *Node) *Node {
```
JavaScript:
```javascript
/**
* // Definition for a Node.
@ -2401,6 +2421,7 @@ var connect = function(root) {
return root;
};
```
TypeScript:
```typescript
@ -2459,6 +2480,7 @@ func connect(_ root: Node?) -> Node? {
```
Scala:
```scala
// 117.填充每个节点的下一个右侧节点指针II
object Solution {
@ -2487,6 +2509,7 @@ object Solution {
}
}
```
# 104.二叉树的最大深度
[力扣题目链接](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)
@ -2501,7 +2524,7 @@ object Solution {
给定二叉树 [3,9,20,null,null,15,7]
![104. 二叉树的最大深度](https://img-blog.csdnimg.cn/20210203153031914.png)
![104. 二叉树的最大深度](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203153031914-20230310134849764.png)
返回它的最大深度 3 。
@ -2511,7 +2534,7 @@ object Solution {
在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,如图所示:
![层序遍历](https://img-blog.csdnimg.cn/20200810193056585.png)
![层序遍历](https://code-thinking-1253855093.file.myqcloud.com/pics/20200810193056585-20230310134854803.png)
所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
@ -2541,6 +2564,7 @@ public:
```
Java
```Java
class Solution {
public int maxDepth(TreeNode root) {
@ -2566,6 +2590,7 @@ class Solution {
```
Python
```python 3
class Solution:
def maxDepth(self, root: TreeNode) -> int:
@ -2623,6 +2648,7 @@ func maxDepth(root *TreeNode) int {
```
JavaScript
```javascript
/**
* Definition for a binary tree node.
@ -2700,6 +2726,7 @@ func maxDepth(_ root: TreeNode?) -> Int {
```
Scala:
```scala
// 104.二叉树的最大深度
object Solution {
@ -2790,6 +2817,7 @@ public:
```
Java
```java
class Solution {
public int minDepth(TreeNode root){
@ -2890,6 +2918,7 @@ func minDepth(root *TreeNode) int {
```
JavaScript
```javascript
/**
* Definition for a binary tree node.
@ -2972,6 +3001,7 @@ func minDepth(_ root: TreeNode?) -> Int {
```
Scala:
```scala
// 111.二叉树的最小深度
object Solution {

View File

@ -18,7 +18,8 @@
示例:
给定二叉树 [3,9,20,null,null,15,7]
![104. 二叉树的最大深度](https://img-blog.csdnimg.cn/20210203153031914.png)
![104. 二叉树的最大深度](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203153031914-20230310121809902.png)
返回它的最大深度 3 。
@ -169,7 +170,8 @@ public:
在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,如图所示:
![层序遍历](https://img-blog.csdnimg.cn/20200810193056585.png)
![层序遍历](https://code-thinking-1253855093.file.myqcloud.com/pics/20200810193056585.png)
所以这道题的迭代法就是一道模板题,可以使用二叉树层序遍历的模板来解决的。
@ -213,7 +215,7 @@ public:
例如,给定一个 3叉树 :
![559.n叉树的最大深度](https://img-blog.csdnimg.cn/2021020315313214.png)
![559.n叉树的最大深度](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020315313214.png)
我们应返回其最大深度3。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
看完本文,可以一起解决如下两道题目
* 106.从中序与后序遍历序列构造二叉树
@ -21,11 +23,11 @@
例如,给出
* 中序遍历 inorder = [9,3,15,20,7]
* 中序遍历 inorder = [9,3,15,20,7]
* 后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
![106. 从中序与后序遍历序列构造二叉树1](https://img-blog.csdnimg.cn/20210203154316774.png)
![106. 从中序与后序遍历序列构造二叉树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203154316774.png)
# 视频讲解
@ -40,7 +42,7 @@
流程如图:
![106.从中序与后序遍历序列构造二叉树](https://img-blog.csdnimg.cn/20210203154249860.png)
![106.从中序与后序遍历序列构造二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203154249860.png)
那么代码应该怎么写呢?
@ -280,6 +282,7 @@ public:
下面给出用下标索引写出的代码版本思路是一样的只不过不用重复定义vector了每次用下标索引来分割
### C++优化版本
```CPP
class Solution {
private:
@ -411,11 +414,11 @@ public:
例如,给出
前序遍历 preorder = [3,9,20,15,7]
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
![105. 从前序与中序遍历序列构造二叉树](https://img-blog.csdnimg.cn/20210203154626672.png)
![105. 从前序与中序遍历序列构造二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203154626672.png)
## 思路
@ -558,7 +561,7 @@ public:
举一个例子:
![106.从中序与后序遍历序列构造二叉树2](https://img-blog.csdnimg.cn/20210203154720326.png)
![106.从中序与后序遍历序列构造二叉树2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203154720326.png)
tree1 的前序遍历是[1 2 3] 后序遍历是[3 2 1]。
@ -653,6 +656,7 @@ class Solution {
```
## Python
```python
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:

View File

@ -17,7 +17,8 @@
示例:
![108.将有序数组转换为二叉搜索树](https://img-blog.csdnimg.cn/20201022164420763.png)
![108.将有序数组转换为二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20201022164420763.png)
# 算法公开课

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 求高度还是求深度,你搞懂了不?
# 110.平衡二叉树
@ -13,13 +15,13 @@
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
![110.平衡二叉树](https://img-blog.csdnimg.cn/2021020315542230.png)
![110.平衡二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020315542230.png)
返回 true 。
@ -27,7 +29,7 @@
给定二叉树 [1,2,2,3,3,null,null,4,4]
![110.平衡二叉树1](https://img-blog.csdnimg.cn/20210203155447919.png)
![110.平衡二叉树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203155447919.png)
返回 false 。
@ -45,7 +47,7 @@
但leetcode中强调的深度和高度很明显是按照节点来计算的如图
![110.平衡二叉树2](https://img-blog.csdnimg.cn/20210203155515650.png)
![110.平衡二叉树2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203155515650.png)
关于根节点的深度究竟是1 还是 0不同的地方有不一样的标准leetcode的题目中都是以节点为一度即根节点深度是1。但维基百科上定义用边为一度即根节点的深度是0我们暂时以leetcode为准毕竟要在这上面刷题
@ -499,6 +501,7 @@ class Solution {
### Python
递归法:
```python
# Definition for a binary tree node.
# class TreeNode:
@ -531,6 +534,7 @@ class Solution:
```
迭代法:
```python
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
@ -557,6 +561,7 @@ class Solution:
### Go
```Go
func isBalanced(root *TreeNode) bool {
h := getHeight(root)
@ -588,7 +593,9 @@ func max(a, b int) int {
```
### JavaScript
递归法:
```javascript
var isBalanced = function(root) {
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
@ -614,6 +621,7 @@ var isBalanced = function(root) {
```
迭代法:
```javascript
// 获取当前节点的高度
var getHeight = function (curNode) {
@ -676,6 +684,7 @@ function isBalanced(root: TreeNode | null): boolean {
### C
递归法:
```c
int getDepth(struct TreeNode* node) {
//如果结点不存在返回0
@ -706,6 +715,7 @@ bool isBalanced(struct TreeNode* root) {
```
迭代法:
```c
//计算结点深度
int getDepth(struct TreeNode* node) {
@ -780,6 +790,7 @@ bool isBalanced(struct TreeNode* root){
### Swift:
>递归
```swift
func isBalanced(_ root: TreeNode?) -> Bool {
// -1 已经不是平衡二叉树

View File

@ -21,7 +21,8 @@
给定二叉树 [3,9,20,null,null,15,7],
![111.二叉树的最小深度1](https://img-blog.csdnimg.cn/2021020315582586.png)
![111.二叉树的最小深度1](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020315582586.png)
返回它的最小深度 2.
@ -45,7 +46,7 @@
本题还有一个误区,在处理节点的过程中,最大深度很容易理解,最小深度就不那么好理解,如图:
![111.二叉树的最小深度](https://img-blog.csdnimg.cn/20210203155800503.png)
![111.二叉树的最小深度](https://code-thinking.cdn.bcebos.com/pics/111.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6.png)
这就重新审题了,题目中说的是:**最小深度是从根节点到最近叶子节点的最短路径上的节点数量。**,注意是**叶子节点**。
@ -87,7 +88,7 @@ return result;
这个代码就犯了此图中的误区:
![111.二叉树的最小深度](https://img-blog.csdnimg.cn/20210203155800503.png)
![111.二叉树的最小深度](https://code-thinking.cdn.bcebos.com/pics/111.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6.png)
如果这么求的话,没有左孩子的分支会算为最短深度。

View File

@ -1,18 +1,20 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 112. 路径总和
[力扣题目链接](https://leetcode.cn/problems/path-sum/)
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
说明: 叶子节点是指没有子节点的节点。
示例: 
示例:
给定如下二叉树,以及目标和 sum = 22
![112.路径总和1](https://img-blog.csdnimg.cn/20210203160355234.png)
@ -53,7 +55,7 @@
如图所示:
![112.路径总和](https://img-blog.csdnimg.cn/2021020316051216.png)
![112.路径总和](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020316051216.png)
图中可以看出遍历的路线并不要遍历整棵树所以递归函数需要返回值可以用bool类型表示。
@ -222,13 +224,13 @@ public:
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22
给定如下二叉树,以及目标和 sum = 22
![113.路径总和ii1.png](https://img-blog.csdnimg.cn/20210203160854654.png)
![113.路径总和ii1.png](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203160854654.png)
## 思路
@ -237,7 +239,7 @@ public:
如图:
![113.路径总和ii](https://img-blog.csdnimg.cn/20210203160922745.png)
![113.路径总和ii](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203160922745.png)
为了尽可能的把细节体现出来,我写出如下代码(**这份代码并不简洁,但是逻辑非常清晰**
@ -303,6 +305,7 @@ public:
## java
### 0112.路径总和
```java
class solution {
public boolean haspathsum(treenode root, int targetsum) {
@ -344,7 +347,9 @@ class solution {
}
}
```
迭代
```java
class solution {
public boolean haspathsum(treenode root, int targetsum) {
@ -447,6 +452,7 @@ class Solution {
### 0112.路径总和
**递归**
```python
class solution:
def haspathsum(self, root: treenode, targetsum: int) -> bool:
@ -472,6 +478,7 @@ class solution:
```
**迭代 - 层序遍历**
```python
class solution:
def haspathsum(self, root: treenode, targetsum: int) -> bool:
@ -499,6 +506,7 @@ class solution:
### 0113.路径总和-ii
**递归**
```python
class solution:
def pathsum(self, root: treenode, targetsum: int) -> list[list[int]]:
@ -528,6 +536,7 @@ class solution:
```
**迭代法,用第二个队列保存目前的总和与路径**
```python
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
@ -623,6 +632,7 @@ func traverse(node *TreeNode, result *[][]int, currPath *[]int, targetSum int) {
### 0112.路径总和
**递归**
```javascript
/**
* @param {treenode} root
@ -652,7 +662,9 @@ let haspathsum = function (root, targetsum) {
// return haspathsum(root.left, targetsum - root.val) || haspathsum(root.right, targetsum - root.val);
};
```
**迭代**
```javascript
let hasPathSum = function(root, targetSum) {
if(root === null) return false;
@ -684,6 +696,7 @@ let hasPathSum = function(root, targetSum) {
### 0113.路径总和-ii
**递归**
```javascript
let pathsum = function (root, targetsum) {
// 递归法
@ -715,7 +728,9 @@ let pathsum = function (root, targetsum) {
return res;
};
```
**递归 精简版**
```javascript
var pathsum = function(root, targetsum) {
//递归方法
@ -739,7 +754,9 @@ var pathsum = function(root, targetsum) {
return resPath;
};
```
**迭代**
```javascript
let pathSum = function(root, targetSum) {
if(root === null) return [];
@ -933,7 +950,9 @@ func traversal(_ cur: TreeNode?, _ count: Int) -> Bool {
return false
}
```
**迭代**
```swift
func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
guard let root = root else {
@ -1015,8 +1034,10 @@ func traversal(_ cur: TreeNode?, count: Int) {
```
## C
> 0112.路径总和
递归法:
> 递归法:
```c
bool hasPathSum(struct TreeNode* root, int targetSum){
// 递归结束条件若当前节点不存在返回false
@ -1032,6 +1053,7 @@ bool hasPathSum(struct TreeNode* root, int targetSum){
```
迭代法:
```c
// 存储一个节点以及当前的和
struct Pair {
@ -1070,7 +1092,9 @@ bool hasPathSum(struct TreeNode* root, int targetSum){
return false;
}
```
> 0113.路径总和 II
```c
int** ret;
int* path;
@ -1139,6 +1163,7 @@ int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** retur
### 0112.路径总和
**递归:**
```scala
object Solution {
def hasPathSum(root: TreeNode, targetSum: Int): Boolean = {
@ -1163,6 +1188,7 @@ object Solution {
```
**迭代:**
```scala
object Solution {
import scala.collection.mutable
@ -1187,6 +1213,7 @@ object Solution {
### 0113.路径总和 II
**递归:**
```scala
object Solution {
import scala.collection.mutable.ListBuffer

View File

@ -127,7 +127,8 @@ dp[0][1]表示第0天不持有股票不持有股票那么现金就是0
以示例1输入[7,1,5,3,6,4]为例dp数组状态如下
![121.买卖股票的最佳时机](https://img-blog.csdnimg.cn/20210224225642465.png)
![121.买卖股票的最佳时机](https://code-thinking-1253855093.file.myqcloud.com/pics/20210224225642465.png)
dp[5][1]就是最终结果。

View File

@ -62,7 +62,8 @@
如图:
![122.买卖股票的最佳时机II](https://img-blog.csdnimg.cn/2020112917480858.png)
![122.买卖股票的最佳时机II](https://code-thinking-1253855093.file.myqcloud.com/pics/2020112917480858-20230310134659477.png)
一些同学陷入:第一天怎么就没有利润呢,第一天到底算不算的困惑中。

View File

@ -116,7 +116,8 @@ dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
以输入[1,2,3,4,5]为例
![123.买卖股票的最佳时机III](https://img-blog.csdnimg.cn/20201228181724295.png)
![123.买卖股票的最佳时机III](https://code-thinking-1253855093.file.myqcloud.com/pics/20201228181724295-20230310134201291.png)
大家可以看到红色框为最后两次卖出的状态。

View File

@ -163,7 +163,7 @@ for (int i = s.size() - 1; i >= 0; i--) {
以输入:"aabc" 为例:
![132.分割回文串II](https://img-blog.csdnimg.cn/20210124182218844.jpg)
![132.分割回文串II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210124182218844.jpg)
以上分析完毕,代码如下:

View File

@ -53,7 +53,8 @@ for (int i = 1; i < ratings.size(); i++) {
如图:
![135.分发糖果](https://img-blog.csdnimg.cn/20201117114916878.png)
![135.分发糖果](https://code-thinking-1253855093.file.myqcloud.com/pics/20201117114916878.png)
再确定左孩子大于右孩子的情况(从后向前遍历)
@ -78,7 +79,8 @@ for (int i = 1; i < ratings.size(); i++) {
如图:
![135.分发糖果1](https://img-blog.csdnimg.cn/20201117115658791.png)
![135.分发糖果1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201117115658791.png)
所以该过程代码如下:

View File

@ -181,7 +181,8 @@ dp[0]表示如果字符串为空的话,说明出现在字典里。
以输入: s = "leetcode", wordDict = ["leet", "code"]为例dp状态如图
![139.单词拆分](https://img-blog.csdnimg.cn/20210202162652727.jpg)
![139.单词拆分](https://code-thinking-1253855093.file.myqcloud.com/pics/20210202162652727.jpg)
dp[s.size()]就是最终结果。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -6,6 +7,7 @@
> 找到有没有环已经很不容易了,还要让我找到环的入口?
@ -14,13 +16,13 @@
[力扣题目链接](https://leetcode.cn/problems/linked-list-cycle-ii/)
题意:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1则在该链表中没有环。
**说明**:不允许修改给定的链表。
![循环链表](https://img-blog.csdnimg.cn/20200816110112704.png)
![循环链表](https://code-thinking-1253855093.file.myqcloud.com/pics/20200816110112704.png)
## 思路
@ -48,7 +50,7 @@
会发现最终都是这种情况, 如下图:
![142环形链表1](https://img-blog.csdnimg.cn/20210318162236720.png)
![142环形链表1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210318162236720.png)
fast和slow各自再走一步 fast和slow就相遇了
@ -149,20 +151,20 @@ public:
即文章[链表:环找到了,那入口呢?](https://programmercarl.com/0142.环形链表II.html)中如下的地方:
![142环形链表5](https://img-blog.csdnimg.cn/20210318165123581.png)
![142环形链表5](https://code-thinking-1253855093.file.myqcloud.com/pics/20210318165123581.png)
首先slow进环的时候fast一定是先进环来了。
如果slow进环入口fast也在环入口那么把这个环展开成直线就是如下图的样子
![142环形链表3](https://img-blog.csdnimg.cn/2021031816503266.png)
![142环形链表3](https://code-thinking-1253855093.file.myqcloud.com/pics/2021031816503266.png)
可以看出如果slow 和 fast同时在环入口开始走一定会在环入口3相遇slow走了一圈fast走了两圈。
重点来了slow进环的时候fast一定是在环的任意一个位置如图
![142环形链表4](https://img-blog.csdnimg.cn/2021031816515727.png)
![142环形链表4](https://code-thinking-1253855093.file.myqcloud.com/pics/2021031816515727.png)
那么fast指针走到环入口3的时候已经走了k + n 个节点slow相应的应该走了(k + n) / 2 个节点。
@ -187,6 +189,7 @@ public:
Java
```java
public class Solution {
public ListNode detectCycle(ListNode head) {
@ -235,6 +238,7 @@ class Solution:
```
Go
```go
func detectCycle(head *ListNode) *ListNode {
slow, fast := head, head
@ -374,6 +378,7 @@ ListNode *detectCycle(ListNode *head) {
```
Scala:
```scala
object Solution {
def detectCycle(head: ListNode): ListNode = {

View File

@ -129,7 +129,7 @@ for (int j = 1; j < 2 * k; j += 2) {
以输入[1,2,3,4,5]k=2为例。
![188.买卖股票的最佳时机IV](https://img-blog.csdnimg.cn/20201229100358221.png)
![188.买卖股票的最佳时机IV](https://code-thinking-1253855093.file.myqcloud.com/pics/20201229100358221.png)
最后一次卖出一定是利润最大的dp[prices.size() - 1][2 * k]即红色部分就是最后求解。

View File

@ -85,7 +85,7 @@ for (int i = 2; i < nums.size(); i++) {
以示例二,输入[2,7,9,3,1]为例。
![198.打家劫舍](https://img-blog.csdnimg.cn/20210221170954115.jpg)
![198.打家劫舍](https://code-thinking-1253855093.file.myqcloud.com/pics/20210221170954115.jpg)
红框dp[nums.size() - 1]为结果。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 链表操作中,可以使用原链表来直接进行删除操作,也可以设置一个虚拟头结点再进行删除操作,接下来看一看哪种方式更方便。
# 203.移除链表元素
@ -32,11 +34,11 @@
这里以链表 1 4 2 4 来举例移除元素4。
![203_链表删除元素1](https://img-blog.csdnimg.cn/20210316095351161.png)
![203_链表删除元素1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210316095351161.png)
如果使用CC++编程语言的话,不要忘了还要从内存中删除这两个移除的节点, 清理节点内存之后如图:
![203_链表删除元素2](https://img-blog.csdnimg.cn/20210316095418280.png)
![203_链表删除元素2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210316095418280.png)
**当然如果使用java python的话就不用手动管理内存了。**
@ -47,23 +49,23 @@
那么因为单链表的特殊性,只能指向下一个节点,刚刚删除的是链表的中第二个,和第四个节点,那么如果删除的是头结点又该怎么办呢?
这里就涉及如下链表操作的两种方式:
* **直接使用原来的链表来进行删除操作。**
* **设置一个虚拟头结点在进行删除操作。**
来看第一种操作:直接使用原来的链表来进行移除。
![203_链表删除元素3](https://img-blog.csdnimg.cn/2021031609544922.png)
![203_链表删除元素3](https://code-thinking-1253855093.file.myqcloud.com/pics/2021031609544922.png)
移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。
所以头结点如何移除呢,其实只要将头结点向后移动一位就可以,这样就从链表中移除了一个头结点。
![203_链表删除元素4](https://img-blog.csdnimg.cn/20210316095512470.png)
![203_链表删除元素4](https://code-thinking-1253855093.file.myqcloud.com/pics/20210316095512470.png)
依然别忘将原头结点从内存中删掉。
![203_链表删除元素5](https://img-blog.csdnimg.cn/20210316095543775.png)
![203_链表删除元素5](https://code-thinking-1253855093.file.myqcloud.com/pics/20210316095543775.png)
这样移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在写代码的时候也会发现,需要单独写一段逻辑来处理移除头结点的情况。
@ -74,7 +76,7 @@
来看看如何设置一个虚拟头。依然还是在这个链表中移除元素1。
![203_链表删除元素6](https://img-blog.csdnimg.cn/20210316095619221.png)
![203_链表删除元素6](https://code-thinking-1253855093.file.myqcloud.com/pics/20210316095619221.png)
这里来给链表添加一个虚拟头结点为新的头结点此时要移除这个旧头结点元素1。
@ -146,8 +148,10 @@ public:
## 其他语言版本
C:
用原来的链表操作:
```c
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* temp;
@ -178,7 +182,9 @@ struct ListNode* removeElements(struct ListNode* head, int val){
return head;
}
```
设置一个虚拟头结点:
```c
/**
* Definition for singly-linked list.
@ -212,6 +218,7 @@ struct ListNode* removeElements(struct ListNode* head, int val){
```
Java
```java
/**
* 添加虚节点方式
@ -292,6 +299,7 @@ public ListNode removeElements(ListNode head, int val) {
```
Python
```python
# Definition for singly-linked list.
# class ListNode:
@ -442,6 +450,7 @@ func removeElements(_ head: ListNode?, _ val: Int) -> ListNode? {
```
PHP:
```php
/**
* Definition for singly-linked list.
@ -469,6 +478,7 @@ func removeElements(head *ListNode, val int) *ListNode {
```
RUST:
```rust
// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Clone, Debug)]
@ -504,7 +514,9 @@ impl Solution {
}
}
```
Scala:
```scala
/**
* Definition for singly-linked list.
@ -535,7 +547,9 @@ object Solution {
}
}
```
Kotlin:
```kotlin
/**
* Example:
@ -569,6 +583,7 @@ class Solution {
}
}
```
<p align="center">
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>

View File

@ -25,7 +25,8 @@
其实只需要改变链表的next指针的指向直接将链表反转 ,而不用重新定义一个新的链表,如图所示:
![206_反转链表](https://img-blog.csdnimg.cn/20210218090901207.png)
![206_反转链表](https://code-thinking-1253855093.file.myqcloud.com/pics/20210218090901207.png)
之前链表的头节点是元素1 反转之后头结点就是元素5 这里并没有添加或者删除节点仅仅是改变next指针的方向。

View File

@ -103,7 +103,7 @@ public:
解题的关键在于 窗口的起始位置如何移动,如图所示:
![leetcode_209](https://img-blog.csdnimg.cn/20210312160441942.png)
![leetcode_209](https://code-thinking-1253855093.file.myqcloud.com/pics/20210312160441942.png)
可以发现**滑动窗口的精妙之处在于根据当前子序列和大小的情况不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。**

View File

@ -39,15 +39,15 @@
* 情况一:考虑不包含首尾元素
![213.打家劫舍II](https://img-blog.csdnimg.cn/20210129160748643.jpg)
![213.打家劫舍II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210129160748643-20230310134000692.jpg)
* 情况二:考虑包含首元素,不包含尾元素
![213.打家劫舍II1](https://img-blog.csdnimg.cn/20210129160821374.jpg)
![213.打家劫舍II1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210129160821374-20230310134003961.jpg)
* 情况三:考虑包含尾元素,不包含首元素
![213.打家劫舍II2](https://img-blog.csdnimg.cn/20210129160842491.jpg)
![213.打家劫舍II2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210129160842491-20230310134008133.jpg)
**注意我这里用的是"考虑"**,例如情况三,虽然是考虑包含尾元素,但不一定要选尾部元素! 对于情况三取nums[1] 和 nums[3]就是最大的。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -7,17 +8,19 @@
> 别看本篇选的是组合总和III而不是组合总和本题和上一篇77.组合相比难度刚刚好!
# 216.组合总和III
[力扣题目链接](https://leetcode.cn/problems/combination-sum-iii/)
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
* 所有数字都是正整数。
* 解集不能包含重复的组合。 
* 解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
@ -46,7 +49,7 @@
选取过程如图:
![216.组合总和III](https://img-blog.csdnimg.cn/20201123195717975.png)
![216.组合总和III](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123195717975.png)
图中可以看出只有最后取到集合13和为4 符合条件。
@ -80,6 +83,7 @@ vector<vector<int>> result;
vector<int> path;
void backtracking(int targetSum, int k, int sum, int startIndex)
```
其实这里sum这个参数也可以省略每次targetSum减去选取的元素数值然后判断如果targetSum为0了说明收集到符合条件的结果了我这里为了直观便于理解还是加一个sum参数。
还要强调一下,回溯法中递归函数参数很难一次性确定下来,一般先写逻辑,需要啥参数了,填什么参数。
@ -108,7 +112,7 @@ if (path.size() == k) {
本题和[77. 组合](https://programmercarl.com/0077.组合.html)区别之一就是集合固定的就是9个数[1,...,9]所以for循环固定i<=9
如图:
![216.组合总和III](https://img-blog.csdnimg.cn/20201123195717975.png)
![216.组合总和III](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123195717975-20230310113546003.png)
处理过程就是 path收集每次选取的元素相当于树型结构里的边sum来统计path里元素的总和。
@ -166,7 +170,7 @@ public:
这道题目,剪枝操作其实是很容易想到了,想必大家看上面的树形图的时候已经想到了。
如图:
![216.组合总和III1](https://img-blog.csdnimg.cn/2020112319580476.png)
![216.组合总和III1](https://code-thinking-1253855093.file.myqcloud.com/pics/2020112319580476.png)
已选元素总和如果已经大于n图中数值为4那么往后遍历就没有意义了直接剪掉。
@ -181,7 +185,6 @@ if (sum > targetSum) { // 剪枝操作
当然这个剪枝也可以放在 调用递归之前,即放在这里,只不过要记得 要回溯操作给做了。
```CPP
for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) { // 剪枝
sum += i; // 处理
path.push_back(i); // 处理
@ -250,6 +253,7 @@ public:
## Java
模板方法
```java
class Solution {
List<List<Integer>> result = new ArrayList<>();
@ -317,6 +321,7 @@ class Solution {
```
其他方法
```java
class Solution {
List<List<Integer>> res = new ArrayList<>();

View File

@ -152,7 +152,7 @@ public:
我来举一个典型的例子如题:
<img src='https://img-blog.csdnimg.cn/20200920221638903.png' width=600> </img></div>
<img src='https://code-thinking-1253855093.file.myqcloud.com/pics/20200920221638903-20230310123444151.png' width=600> </img>
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
@ -161,10 +161,10 @@ public:
对于情况二分别递归左孩子和右孩子递归到某一深度一定会有左孩子或者右孩子为满二叉树然后依然可以按照情况1来计算。
完全二叉树(一)如图:
![222.完全二叉树的节点个数](https://img-blog.csdnimg.cn/20201124092543662.png)
![222.完全二叉树的节点个数](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124092543662.png)
完全二叉树(二)如图:
![222.完全二叉树的节点个数1](https://img-blog.csdnimg.cn/20201124092634138.png)
![222.完全二叉树的节点个数1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124092634138.png)
可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。

View File

@ -11,7 +11,8 @@
翻转一棵二叉树。
![226.翻转二叉树](https://img-blog.csdnimg.cn/20210203192644329.png)
![226.翻转二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203192644329.png)
这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell就是因为没在白板上写出翻转二叉树最后被Google拒绝了。真假不做判断权当一个乐子哈
@ -33,7 +34,8 @@
如果要从整个树来看,翻转还真的挺复杂,整个树以中间分割线进行翻转,如图:
![226.翻转二叉树1](https://img-blog.csdnimg.cn/20210203192724351.png)
![226.翻转二叉树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210203192724351.png)
可以发现想要翻转它,其实就把每一个节点的左右孩子交换一下就可以了。

View File

@ -15,7 +15,8 @@
例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]
![235. 二叉搜索树的最近公共祖先](https://img-blog.csdnimg.cn/20201018172243602.png)
![235. 二叉搜索树的最近公共祖先](https://code-thinking-1253855093.file.myqcloud.com/pics/20201018172243602.png)
示例 1:

View File

@ -17,7 +17,8 @@
例如,给定如下二叉树:  root = [3,5,1,6,2,0,8,null,null,7,4]
![236. 二叉树的最近公共祖先](https://img-blog.csdnimg.cn/20201016173414722.png)
![236. 二叉树的最近公共祖先](https://code-thinking-1253855093.file.myqcloud.com/pics/20201016173414722.png)
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
@ -130,7 +131,7 @@ left与right的逻辑处理; // 中
如图:
![236.二叉树的最近公共祖先](https://img-blog.csdnimg.cn/2021020415105872.png)
![236.二叉树的最近公共祖先](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020415105872.png)
就像图中一样直接返回7多美滋滋。
@ -163,7 +164,7 @@ TreeNode* right = lowestCommonAncestor(root->right, p, q);
如图:
![236.二叉树的最近公共祖先1](https://img-blog.csdnimg.cn/20210204151125844.png)
![236.二叉树的最近公共祖先1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204151125844.png)
图中节点10的左子树返回null右子树返回目标值7那么此时节点10的处理逻辑就是把右子树的返回值最近公共祖先7返回上去
@ -184,7 +185,7 @@ else { // (left == NULL && right == NULL)
那么寻找最小公共祖先,完整流程图如下:
![236.二叉树的最近公共祖先2](https://img-blog.csdnimg.cn/202102041512582.png)
![236.二叉树的最近公共祖先2](https://code-thinking-1253855093.file.myqcloud.com/pics/202102041512582.png)
**从图中,大家可以看到,我们是如何回溯遍历整棵二叉树,将结果返回给头结点的!**

View File

@ -16,7 +16,7 @@
说明: 叶子节点是指没有子节点的节点。
示例:
![257.二叉树的所有路径1](https://img-blog.csdnimg.cn/2021020415161576.png)
![257.二叉树的所有路径1](https://code-thinking-1253855093.file.myqcloud.com/pics/2021020415161576.png)
# 思路
@ -28,7 +28,7 @@
前序遍历以及回溯的过程如图:
![257.二叉树的所有路径](https://img-blog.csdnimg.cn/20210204151702443.png)
![257.二叉树的所有路径](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204151702443.png)
我们先使用递归的方式,来做前序遍历。**要知道递归和回溯就是一家的,本题也需要回溯。**

View File

@ -94,7 +94,8 @@ for (int i = 0; i <= n; i++) { // 遍历背包
已输入n为5例dp状态图如下
![279.完全平方数](https://img-blog.csdnimg.cn/20210202112617341.jpg)
![279.完全平方数](https://code-thinking-1253855093.file.myqcloud.com/pics/20210202112617341.jpg)
dp[0] = 0
dp[1] = min(dp[0] + 1) = 1

View File

@ -82,7 +82,7 @@ for (int i = 1; i < nums.size(); i++) {
输入:[0,1,0,3,2]dp数组的变化如下
![300.最长上升子序列](https://img-blog.csdnimg.cn/20210110170945618.jpg)
![300.最长上升子序列](https://code-thinking-1253855093.file.myqcloud.com/pics/20210110170945618.jpg)
如果代码写出来但一直AC不了那么就把dp数组打印出来看看对不对

View File

@ -45,7 +45,7 @@ dp[i][j]第i天状态为j所剩的最多现金为dp[i][j]。
* 状态三:今天卖出股票
* 状态四:今天为冷冻期状态,但冷冻期状态不可持续,只有一天!
![](https://img-blog.csdnimg.cn/518d5baaf33f4b2698064f8efb42edbf.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/518d5baaf33f4b2698064f8efb42edbf.png)
j的状态为
@ -133,7 +133,8 @@ dp[i][3] = dp[i - 1][2];
以 [1,2,3,0,2] 为例dp数组如下
![309.最佳买卖股票时机含冷冻期](https://img-blog.csdnimg.cn/2021032317451040.png)
![309.最佳买卖股票时机含冷冻期](https://code-thinking-1253855093.file.myqcloud.com/pics/2021032317451040.png)
最后结果是取 状态二,状态三,和状态四的最大值,不少同学会把状态四忘了,状态四是冷冻期,最后一天如果是冷冻期也可能是最大值。

View File

@ -106,7 +106,7 @@ dp[0] = 0;
以输入coins = [1, 2, 5], amount = 5为例
![322.零钱兑换](https://img-blog.csdnimg.cn/20210201111833906.jpg)
![322.零钱兑换](https://code-thinking-1253855093.file.myqcloud.com/pics/20210201111833906.jpg)
dp[amount]为最终结果。

View File

@ -57,7 +57,7 @@
对于死循环,我来举一个有重复机场的例子:
![332.重新安排行程](https://img-blog.csdnimg.cn/20201115180537865.png)
![332.重新安排行程](https://code-thinking-1253855093.file.myqcloud.com/pics/20201115180537865.png)
为什么要举这个例子呢,就是告诉大家,出发机场和到达机场也会重复的,**如果在解题的过程中没有对集合元素处理好,就会死循环。**
@ -111,7 +111,7 @@ void backtracking(参数) {
本题以输入:[["JFK", "KUL"], ["JFK", "NRT"], ["NRT", "JFK"]为例,抽象为树形结构如下:
![332.重新安排行程1](https://img-blog.csdnimg.cn/2020111518065555.png)
![332.重新安排行程1](https://code-thinking-1253855093.file.myqcloud.com/pics/2020111518065555-20230310121223600.png)
开始回溯三部曲讲解:
@ -137,7 +137,7 @@ bool backtracking(int ticketNum, vector<string>& result) {
因为我们只需要找到一个行程,就是在树形结构中唯一的一条通向叶子节点的路线,如图:
![332.重新安排行程1](https://img-blog.csdnimg.cn/2020111518065555.png)
![332.重新安排行程1](https://code-thinking-1253855093.file.myqcloud.com/pics/2020111518065555-20230310121240991.png)
所以找到了这个叶子节点了直接返回,这个递归函数的返回值问题我们在讲解二叉树的系列的时候,在这篇[二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?](https://programmercarl.com/0112.路径总和.html)详细介绍过。

View File

@ -13,7 +13,8 @@
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
![337.打家劫舍III](https://img-blog.csdnimg.cn/20210223173849619.png)
![337.打家劫舍III](https://code-thinking-1253855093.file.myqcloud.com/pics/20210223173849619.png)
## 思路

View File

@ -129,7 +129,7 @@ for (int i = 3; i <= n ; i++) {
举例当n为10 的时候dp数组里的数值如下
![343.整数拆分](https://img-blog.csdnimg.cn/20210104173021581.png)
![343.整数拆分](https://code-thinking-1253855093.file.myqcloud.com/pics/20210104173021581.png)
以上动规五部曲分析完毕C++代码如下:

View File

@ -16,7 +16,7 @@
题意:给定两个数组,编写一个函数来计算它们的交集。
![349. 两个数组的交集](https://img-blog.csdnimg.cn/20200818193523911.png)
![349. 两个数组的交集](https://code-thinking-1253855093.file.myqcloud.com/pics/20200818193523911.png)
**说明:**
输出结果中的每个元素一定是唯一的。

View File

@ -41,7 +41,7 @@
用示例二来举例,如图所示:
![376.摆动序列](https://img-blog.csdnimg.cn/20201124174327597.png)
![376.摆动序列](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124174327597.png)
**局部最优:删除单调坡度上的节点(不包括单调坡度两端的节点),那么这个坡度就可以有两个局部峰值**。
@ -103,7 +103,7 @@
那么为了规则统一,针对序列[2,5],可以假设为[2,2,5]这样它就有坡度了即preDiff = 0如图
![376.摆动序列1](https://img-blog.csdnimg.cn/20201124174357612.png)
![376.摆动序列1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124174357612.png)
针对以上情形result初始为1默认最右面有一个峰值此时curDiff > 0 && preDiff <= 0那么result++计算了左面的峰值最后得到的result就是2峰值个数为2即摆动序列长度为2

View File

@ -105,7 +105,7 @@ dp[i]考虑nums[j])可以由 dp[i - nums[j]]不考虑nums[j] 推导
我们再来用示例中的例子推导一下:
![377.组合总和Ⅳ](https://img-blog.csdnimg.cn/20210131174250148.jpg)
![377.组合总和Ⅳ](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000625.png)
如果代码运行处的结果不是想要的结果就把dp[i]都打出来,看看和我们推导的一不一样。

View File

@ -77,7 +77,8 @@ if (s[i - 1] != t[j - 1])此时相当于t要删除元素t如果把当前
因为这样的定义在dp二维矩阵中可以留出初始化的区间如图
![392.判断子序列](https://img-blog.csdnimg.cn/20210303173115966.png)
![392.判断子序列](https://code-thinking-1253855093.file.myqcloud.com/pics/20210303173115966.png)
如果要是定义的dp[i][j]是以下标i为结尾的字符串s和以下标j为结尾的字符串t初始化就比较麻烦了。
@ -94,13 +95,15 @@ vector<vector<int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0));
如图所示:
![392.判断子序列1](https://img-blog.csdnimg.cn/20210303172354155.jpg)
![392.判断子序列1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210303172354155.jpg)
5. 举例推导dp数组
以示例一为例输入s = "abc", t = "ahbgdc"dp状态转移图如下
![392.判断子序列2](https://img-blog.csdnimg.cn/2021030317364166.jpg)
![392.判断子序列2](https://code-thinking-1253855093.file.myqcloud.com/pics/2021030317364166.jpg)
dp[i][j]表示以下标i-1为结尾的字符串s和以下标j-1为结尾的字符串t 相同子序列的长度所以如果dp[s.size()][t.size()] 与 字符串s的长度相同说明s与t的最长相同子序列就是s那么s 就是 t 的子序列。

View File

@ -13,7 +13,8 @@
示例:
![404.左叶子之和1](https://img-blog.csdnimg.cn/20210204151927654.png)
![404.左叶子之和1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204151927654.png)
## 视频讲解
@ -27,8 +28,7 @@
大家思考一下如下图中二叉树,左叶子之和究竟是多少?
![404.左叶子之和](https://img-blog.csdnimg.cn/20210204151949672.png)
![404.左叶子之和](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204151949672.png)
**其实是0因为这棵树根本没有左叶子**
但看这个图的左叶子之和是多少?

View File

@ -59,7 +59,7 @@
以图中{5,2} 为例:
![406.根据身高重建队列](https://img-blog.csdnimg.cn/20201216201851982.png)
![406.根据身高重建队列](https://code-thinking-1253855093.file.myqcloud.com/pics/20201216201851982.png)
按照身高排序之后优先按身高高的people的k来插入后序插入节点也不会影响前面已经插入的节点最终按照k的规则完成了队列。

View File

@ -148,7 +148,8 @@ dp[j]的数值一定是小于等于j的。
用例1输入[1,5,11,5] 为例,如图:
![416.分割等和子集2](https://img-blog.csdnimg.cn/20210110104240545.png)
![416.分割等和子集2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210110104240545.png)
最后dp[11] == 11说明可以将这个数组分割成两个子集使得两个子集的元素和相等。

View File

@ -21,7 +21,8 @@
示例:
![450.删除二叉搜索树中的节点](https://img-blog.csdnimg.cn/20201020171048265.png)
![450.删除二叉搜索树中的节点](https://code-thinking-1253855093.file.myqcloud.com/pics/20201020171048265.png)
# 算法公开课

View File

@ -74,7 +74,7 @@
以题目示例: [[10,16],[2,8],[1,6],[7,12]]为例,如图:(方便起见,已经排序)
![452.用最少数量的箭引爆气球](https://img-blog.csdnimg.cn/20201123101929791.png)
![452.用最少数量的箭引爆气球](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123101929791.png)
可以看出首先第一组重叠气球一定是需要一个箭气球3的左边界大于了 第一组重叠气球的最小右边界所以再需要一支箭来射气球3了。

View File

@ -52,7 +52,8 @@
其实本题并不是多重背包,再来看一下这个图,捋清几种背包的关系
![416.分割等和子集1](https://img-blog.csdnimg.cn/20210117171307407.png)
![416.分割等和子集1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210117171307407-20230310132423205.png)
多重背包是每个物品,数量不同的情况。
@ -128,7 +129,7 @@ for (string str : strs) { // 遍历物品
最后dp数组的状态如下所示
![474.一和零](https://img-blog.csdnimg.cn/20210120111201512.jpg)
![474.一和零](https://code-thinking-1253855093.file.myqcloud.com/pics/20210120111201512.jpg)
以上动规五部曲分析完毕C++代码如下:

View File

@ -46,7 +46,10 @@
为了有鲜明的对比,我用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:
![491. 递增子序列1](https://img-blog.csdnimg.cn/20201124200229824.png)
![491. 递增子序列1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124200229824.png)
### 回溯三部曲
@ -78,7 +81,7 @@ if (path.size() > 1) {
* 单层搜索逻辑
![491. 递增子序列1](https://img-blog.csdnimg.cn/20201124200229824.png)
![491. 递增子序列1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201124200229824-20230310131640070.png)
在图中可以看出,**同一父节点下的同层上使用过的元素就不能再使用了**
那么单层搜索代码如下:

View File

@ -219,7 +219,7 @@ bagSize = (S + sum) / 2 = (3 + 5) / 2 = 4
dp数组状态变化如下
![494.目标和](https://img-blog.csdnimg.cn/20210125120743274.jpg)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20210125120743274.jpg)
C++代码如下:

View File

@ -25,7 +25,7 @@
给定 BST [1,null,2,2],
![501. 二叉搜索树中的众数](https://img-blog.csdnimg.cn/20201014221532206.png)
![501. 二叉搜索树中的众数](https://code-thinking-1253855093.file.myqcloud.com/pics/20201014221532206.png)
返回[2].
@ -146,7 +146,7 @@ public:
如图:
![501.二叉搜索树中的众数1](https://img-blog.csdnimg.cn/20210204152758889.png)
![501.二叉搜索树中的众数1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204152758889.png)
中序遍历代码如下:

View File

@ -11,13 +11,14 @@
给定一个二叉树,在树的最后一行找到最左边的值。
示例 1:
![513.找树左下角的值](https://img-blog.csdnimg.cn/20210204152956836.png)
![513.找树左下角的值](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204152956836.png)
示例 2:
![513.找树左下角的值1](https://img-blog.csdnimg.cn/20210204153017586.png)
![513.找树左下角的值1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204153017586.png)
## 视频讲解

View File

@ -1,9 +1,11 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 516.最长回文子序列
[力扣题目链接](https://leetcode.cn/problems/longest-palindromic-subsequence/)
@ -52,7 +54,7 @@
如果s[i]与s[j]相同那么dp[i][j] = dp[i + 1][j - 1] + 2;
如图:
![516.最长回文子序列](https://img-blog.csdnimg.cn/20210127151350563.jpg)
![516.最长回文子序列](https://code-thinking-1253855093.file.myqcloud.com/pics/20210127151350563.jpg)
如果这里看不懂回忆一下dp[i][j]的定义)
@ -64,7 +66,7 @@
那么dp[i][j]一定是取最大的dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
![516.最长回文子序列1](https://img-blog.csdnimg.cn/20210127151420476.jpg)
![516.最长回文子序列1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210127151420476.jpg)
代码如下:
@ -117,7 +119,7 @@ for (int i = s.size() - 1; i >= 0; i--) {
输入s:"cbbd" 为例dp数组状态如图
![516.最长回文子序列3](https://img-blog.csdnimg.cn/20210127151521432.jpg)
![516.最长回文子序列3](https://code-thinking-1253855093.file.myqcloud.com/pics/20210127151521432.jpg)
红色框即dp[0][s.size() - 1]; 为最终结果。
@ -147,6 +149,7 @@ public:
Java
```java
public class Solution {
public int longestPalindromeSubseq(String s) {
@ -169,6 +172,7 @@ public class Solution {
Python
```python
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
@ -185,6 +189,7 @@ class Solution:
```
Go
```Go
func longestPalindromeSubseq(s string) int {
size := len(s)
@ -213,6 +218,7 @@ func longestPalindromeSubseq(s string) int {
```
Javascript
```javascript
const longestPalindromeSubseq = (s) => {
const strLen = s.length;

View File

@ -158,7 +158,7 @@ for (int j = 0; j <= amount; j++) { // 遍历背包容量
输入: amount = 5, coins = [1, 2, 5] dp状态图如下
![518.零钱兑换II](https://img-blog.csdnimg.cn/20210120181331461.jpg)
![518.零钱兑换II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210120181331461.jpg)
最后红色框dp[amount]为最终结果。

View File

@ -15,7 +15,7 @@
示例:
![530二叉搜索树的最小绝对差](https://img-blog.csdnimg.cn/20201014223400123.png)
![530二叉搜索树的最小绝对差](https://code-thinking-1253855093.file.myqcloud.com/pics/20201014223400123.png)
提示:树中至少有 2 个节点。
@ -72,7 +72,7 @@ public:
如图:
![530.二叉搜索树的最小绝对差](https://img-blog.csdnimg.cn/20210204153247458.png)
![530.二叉搜索树的最小绝对差](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204153247458.png)
一些同学不知道在递归中如何记录前一个节点的指针,其实实现起来是很简单的,大家只要看过一次,写过一次,就掌握了。

View File

@ -19,7 +19,8 @@
示例 1
![538.把二叉搜索树转换为累加树](https://img-blog.csdnimg.cn/20201023160751832.png)
![538.把二叉搜索树转换为累加树](https://code-thinking-1253855093.file.myqcloud.com/pics/20201023160751832.png)
* 输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
* 输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
@ -67,7 +68,8 @@
遍历顺序如图所示:
![538.把二叉搜索树转换为累加树](https://img-blog.csdnimg.cn/20210204153440666.png)
![538.把二叉搜索树转换为累加树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204153440666.png)
本题依然需要一个pre指针记录当前遍历节点cur的前一个节点这样才方便做累加。

View File

@ -78,7 +78,7 @@ for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
以word1:"sea"word2:"eat"为例推导dp数组状态图如下
![583.两个字符串的删除操作1](https://img-blog.csdnimg.cn/20210714101750205.png)
![583.两个字符串的删除操作1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210714101750205.png)
以上分析完毕,代码如下:

View File

@ -15,7 +15,7 @@
示例 1:
![617.合并二叉树](https://img-blog.csdnimg.cn/20210204153634809.png)
![617.合并二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000854.png)
注意: 合并必须从两个树的根节点开始。

View File

@ -102,7 +102,7 @@ dp[i][j]可以初始化为true么 当然不行,怎能刚开始就全都匹
dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:
![647.回文子串](https://img-blog.csdnimg.cn/20210121171032473.jpg)
![647.回文子串](https://code-thinking-1253855093.file.myqcloud.com/pics/20210121171032473-20230310132134822.jpg)
如果这矩阵是从上到下从左到右遍历那么会用到没有计算过的dp[i + 1][j - 1],也就是根据不确定是不是回文的区间[i+1,j-1],来判断了[i,j]是不是回文,那结果一定是不对的。
@ -132,7 +132,7 @@ for (int i = s.size() - 1; i >= 0; i--) { // 注意遍历顺序
举例,输入:"aaa"dp[i][j]状态如下:
![647.回文子串1](https://img-blog.csdnimg.cn/20210121171059951.jpg)
![647.回文子串1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210121171059951-20230310132153163.jpg)
图中有6个true所以就是有6个回文子串。

View File

@ -19,7 +19,7 @@
示例
![654.最大二叉树](https://img-blog.csdnimg.cn/20210204154534796.png)
![654.最大二叉树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204154534796.png)
提示:

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
> 如果不对递归有深刻的理解,本题有点难
> 单纯移除一个节点那还不够,要修剪!
@ -12,11 +14,11 @@
[力扣题目链接](https://leetcode.cn/problems/trim-a-binary-search-tree/)
给定一个二叉搜索树同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
给定一个二叉搜索树同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。
![669.修剪二叉搜索树](https://img-blog.csdnimg.cn/20201014173115788.png)
![669.修剪二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20201014173115788.png)
![669.修剪二叉搜索树1](https://img-blog.csdnimg.cn/20201014173219142.png)
![669.修剪二叉搜索树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201014173219142.png)
# 算法公开课
@ -50,7 +52,7 @@ public:
我们在重新关注一下第二个示例,如图:
![669.修剪二叉搜索树](https://img-blog.csdnimg.cn/20210204155302751.png)
![669.修剪二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204155302751.png)
**所以以上的代码是不可行的!**
@ -60,7 +62,7 @@ public:
在上图中我们发现节点0并不符合区间要求那么将节点0的右孩子 节点2 直接赋给 节点3的左孩子就可以了就是把节点0从二叉树中移除如图
![669.修剪二叉搜索树1](https://img-blog.csdnimg.cn/20210204155327203.png)
![669.修剪二叉搜索树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204155327203.png)
理解了最关键部分了我们再递归三部曲:
@ -127,9 +129,10 @@ return root;
在回顾一下上面的代码,针对下图中二叉树的情况:
![669.修剪二叉搜索树1](https://img-blog.csdnimg.cn/20210204155327203.png)
![669.修剪二叉搜索树1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204155327203-20230310120126738.png)
如下代码相当于把节点0的右孩子节点2返回给上一层
```
if (root->val < low) {
TreeNode* right = trimBST(root->right, low, high); // 寻找符合区间[low, high]的节点
@ -267,7 +270,9 @@ class Solution {
```
## Python
**递归**
```python
# Definition for a binary tree node.
# class TreeNode:
@ -300,6 +305,7 @@ class Solution:
```
**迭代**
```python
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
@ -328,7 +334,6 @@ class Solution:
## Go
```go
// 递归
func trimBST(root *TreeNode, low int, high int) *TreeNode {
if root == nil {
@ -384,6 +389,7 @@ func trimBST(root *TreeNode, low int, high int) *TreeNode {
## JavaScript版本
迭代:
```js
var trimBST = function(root, low, high) {
if(root === null) {
@ -416,6 +422,7 @@ var trimBST = function(root, low, high) {
```
递归:
```js
var trimBST = function (root,low,high) {
if(root === null) {
@ -486,6 +493,7 @@ function trimBST(root: TreeNode | null, low: number, high: number): TreeNode | n
## Scala
递归法:
```scala
object Solution {
def trimBST(root: TreeNode, low: Int, high: Int): TreeNode = {
@ -502,6 +510,7 @@ object Solution {
## rust
// 递归
```rust
impl Solution {
pub fn trim_bst(

View File

@ -180,7 +180,7 @@ for (int i = 0; i < nums.size(); i++) {
输入:[1,3,5,4,7]
![673.最长递增子序列的个数](https://img-blog.csdnimg.cn/20210112104555234.jpg)
![673.最长递增子序列的个数](https://code-thinking-1253855093.file.myqcloud.com/pics/20230310000656.png)
**如果代码写出来了怎么改都通过不了那么把dp和count打印出来看看对不对**

View File

@ -82,7 +82,8 @@ for (int i = 1; i < nums.size(); i++) {
已输入nums = [1,3,5,4,7]为例dp数组状态如下
![674.最长连续递增序列](https://img-blog.csdnimg.cn/20210204103529742.jpg)
![674.最长连续递增序列](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204103529742.jpg)
**注意这里要取dp[i]里的最大值所以dp[2]才是结果!**

View File

@ -13,7 +13,8 @@
例如,
![700.二叉搜索树中的搜索](https://img-blog.csdnimg.cn/20210204155522476.png)
![700.二叉搜索树中的搜索](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204155522476.png)
在上述示例中,如果要找的值是 5但因为没有节点值为 5我们应该返回 NULL。
@ -125,7 +126,7 @@ public:
中间节点如果大于3就向左走如果小于3就向右走如图
![二叉搜索树](https://img-blog.csdnimg.cn/20200812190213280.png)
![二叉搜索树](https://code-thinking-1253855093.file.myqcloud.com/pics/20200812190213280.png)
所以迭代法代码如下:

View File

@ -13,7 +13,8 @@
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。
![701.二叉搜索树中的插入操作](https://img-blog.csdnimg.cn/20201019173259554.png)
![701.二叉搜索树中的插入操作](https://code-thinking-1253855093.file.myqcloud.com/pics/20201019173259554.png)
提示:

View File

@ -59,7 +59,7 @@
例如在数组1,2,3,4,7,9,10中查找元素2如图所示
![704.二分查找](https://img-blog.csdnimg.cn/20210311153055723.jpg)
![704.二分查找](https://code-thinking-1253855093.file.myqcloud.com/pics/20210311153055723.jpg)
代码如下:(详细注释)
@ -98,7 +98,8 @@ public:
在数组1,2,3,4,7,9,10中查找元素2如图所示**注意和方法一的区别**
![704.二分查找1](https://img-blog.csdnimg.cn/20210311153123632.jpg)
![704.二分查找1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210311153123632.jpg)
代码如下:(详细注释)

View File

@ -22,7 +22,7 @@
* deleteAtIndex(index)如果索引 index 有效则删除链表中的第 index 个节点。
![707示例](https://img-blog.csdnimg.cn/20200814200558953.png)
![707示例](https://code-thinking-1253855093.file.myqcloud.com/pics/20200814200558953.png)
# 思路
@ -33,10 +33,10 @@
如果对链表的虚拟头结点不清楚,可以看这篇文章:[链表:听说用虚拟头节点会方便很多?](https://programmercarl.com/0203.移除链表元素.html)
删除链表节点:
![链表-删除节点](https://img-blog.csdnimg.cn/20200806195114541.png)
![链表-删除节点](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806195114541.png)
添加链表节点:
![链表-添加节点](https://img-blog.csdnimg.cn/20200806195134331.png)
![链表-添加节点](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806195134331.png)
这道题目设计链表的五个接口:
* 获取链表第index个节点的数值

View File

@ -93,7 +93,8 @@ for (int i = 1; i <= nums1.size(); i++) {
拿示例1中A: [1,2,3,2,1]B: [3,2,1,4,7]为例画一个dp数组的状态变化如下
![718.最长重复子数组](https://img-blog.csdnimg.cn/2021011215282060.jpg)
![718.最长重复子数组](https://code-thinking-1253855093.file.myqcloud.com/pics/2021011215282060.jpg)
以上五部曲分析完毕C++代码如下:
@ -124,7 +125,8 @@ public:
在如下图中:
![718.最长重复子数组](https://img-blog.csdnimg.cn/2021011215282060.jpg)
![718.最长重复子数组](https://code-thinking-1253855093.file.myqcloud.com/pics/2021011215282060-20230310134554486.jpg)
我们可以看出dp[i][j]都是由dp[i - 1][j - 1]推出。那么压缩为一维数组也就是dp[j]都是由dp[j - 1]推出。

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,15 +6,16 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 739. 每日温度
[力扣题目链接](https://leetcode.cn/problems/daily-temperatures/)
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
## 思路
@ -59,13 +61,13 @@
**把这三种情况分析清楚了,也就理解透彻了**。
接下来我们用temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
接下来我们用temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
-------
首先先将第一个遍历元素加入单调栈
![739.每日温度1](https://img-blog.csdnimg.cn/20210219124434172.jpg)
![739.每日温度1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124434172.jpg)
---------
@ -73,65 +75,65 @@
我们要保持一个递增单调栈从栈头到栈底所以将T[0]弹出T[1]加入此时result数组可以记录了result[0] = 1即T[0]右面第一个比T[0]大的元素是T[1]。
![739.每日温度2](https://img-blog.csdnimg.cn/20210219124504299.jpg)
![739.每日温度2](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124504299.jpg)
-----------
加入T[2]同理T[1]弹出
![739.每日温度3](https://img-blog.csdnimg.cn/20210219124527361.jpg)
![739.每日温度3](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124527361.jpg)
-------
加入T[3]T[3] < T[2] 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况加T[3]加入单调栈
![739.每日温度4](https://img-blog.csdnimg.cn/20210219124610761.jpg)
![739.每日温度4](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124610761.jpg)
---------
加入T[4]T[4] == T[3] 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!
![739.每日温度5](https://img-blog.csdnimg.cn/20210219124633444.jpg)
![739.每日温度5](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124633444.jpg)
---------
加入T[5]T[5] > T[4] 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况将T[4]弹出同时计算距离更新result
![739.每日温度6](https://img-blog.csdnimg.cn/20210219124700567.jpg)
![739.每日温度6](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124700567.jpg)
----------
T[4]弹出之后, T[5] > T[3] 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况将T[3]继续弹出同时计算距离更新result
![739.每日温度7](https://img-blog.csdnimg.cn/20210219124726613.jpg)
![739.每日温度7](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124726613.jpg)
-------
直到发现T[5]小于T[st.top()]终止弹出将T[5]加入单调栈
![739.每日温度8](https://img-blog.csdnimg.cn/20210219124807715.jpg)
![739.每日温度8](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124807715.jpg)
-------
加入T[6]同理需要将栈里的T[5]T[2]弹出
![739.每日温度9](https://img-blog.csdnimg.cn/2021021912483374.jpg)
![739.每日温度9](https://code-thinking-1253855093.file.myqcloud.com/pics/2021021912483374.jpg)
-------
同理,继续弹出
![739.每日温度10](https://img-blog.csdnimg.cn/2021021912490098.jpg)
![739.每日温度10](https://code-thinking-1253855093.file.myqcloud.com/pics/2021021912490098.jpg)
------
此时栈里只剩下了T[6]
![739.每日温度11](https://img-blog.csdnimg.cn/20210219124930156.jpg)
![739.每日温度11](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124930156.jpg)
------------
加入T[7] T[7] < T[6] 直接入栈这就是最后的情况result数组也更新完了
![739.每日温度12](https://img-blog.csdnimg.cn/20210219124957216.jpg)
![739.每日温度12](https://code-thinking-1253855093.file.myqcloud.com/pics/20210219124957216.jpg)
此时有同学可能就疑惑了那result[6] , result[7]怎么没更新啊,元素也一直在栈里。
@ -198,6 +200,7 @@ public:
}
};
```
* 时间复杂度O(n)
* 空间复杂度O(n)
@ -210,8 +213,8 @@ public:
Java
```java
```java
class Solution {
// 版本 1
public int[] dailyTemperatures(int[] temperatures) {
@ -266,7 +269,9 @@ class Solution {
}
```
Python
```python
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
@ -285,6 +290,7 @@ class Solution:
return answer
```
Go
> 暴力法
@ -341,6 +347,7 @@ func dailyTemperatures(temperatures []int) []int {
```
> 单调栈法(精简版本)
```go
// 单调递减栈
func dailyTemperatures(num []int) []int {
@ -362,6 +369,7 @@ func dailyTemperatures(num []int) []int {
```
JavaScript
```javascript
// 版本一
var dailyTemperatures = function(temperatures) {

View File

@ -41,7 +41,8 @@
如图:
![763.划分字母区间](https://img-blog.csdnimg.cn/20201222191924417.png)
![763.划分字母区间](https://code-thinking-1253855093.file.myqcloud.com/pics/20201222191924417.png)
明白原理之后,代码并不复杂,如下:

View File

@ -1,3 +1,4 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
@ -5,6 +6,7 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 968.监控二叉树
[力扣题目链接](https://leetcode.cn/problems/binary-tree-cameras/)
@ -17,7 +19,7 @@
示例 1
![](https://img-blog.csdnimg.cn/20201229175736596.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20201229175736596.png)
* 输入:[0,0,null,0,0]
* 输出1
@ -25,7 +27,7 @@
示例 2
![](https://img-blog.csdnimg.cn/2020122917584449.png)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/2020122917584449.png)
* 输入:[0,0,null,0,null,0,null,null,0]
* 输出2
@ -139,7 +141,7 @@ if (cur == NULL) return 2;
如图:
![968.监控二叉树2](https://img-blog.csdnimg.cn/20201229203710729.png)
![968.监控二叉树2](https://code-thinking-1253855093.file.myqcloud.com/pics/20201229203710729.png)
代码如下:
@ -163,6 +165,7 @@ if (left == 2 && right == 2) return 0;
此时摄像头的数量要加一并且return 1代表中间节点放摄像头。
代码如下:
```CPP
if (left == 0 || right == 0) {
result++;
@ -186,7 +189,7 @@ if (left == 1 || right == 1) return 2;
**从这个代码中可以看出如果left == 1, right == 0 怎么办其实这种条件在情况2中已经判断过了**,如图:
![968.监控二叉树1](https://img-blog.csdnimg.cn/2020122920362355.png)
![968.监控二叉树1](https://code-thinking-1253855093.file.myqcloud.com/pics/2020122920362355.png)
这种情况也是大多数同学容易迷惑的情况。
@ -194,7 +197,7 @@ if (left == 1 || right == 1) return 2;
以上都处理完了,递归结束之后,可能头结点 还有一个无覆盖的情况,如图:
![968.监控二叉树3](https://img-blog.csdnimg.cn/20201229203742446.png)
![968.监控二叉树3](https://code-thinking-1253855093.file.myqcloud.com/pics/20201229203742446.png)
所以递归结束之后还要判断根节点如果没有覆盖result++,代码如下:
@ -312,6 +315,7 @@ public:
### Java
```java
class Solution {
int res=0;
@ -358,6 +362,7 @@ class Solution {
### Python
```python
class Solution:
def minCameraCover(self, root: TreeNode) -> int:
@ -408,6 +413,7 @@ class Solution:
```
### Go
```go
const inf = math.MaxInt64 / 2
@ -438,6 +444,7 @@ func min(a, b int) int {
```
### Javascript
```Javascript
var minCameraCover = function(root) {
let result = 0
@ -576,7 +583,9 @@ object Solution {
}
}
```
### Rust
```Rust
/// 版本一
impl Solution {

View File

@ -14,7 +14,8 @@
以这种方法绘制线条,并返回我们可以绘制的最大连线数。
![1035.不相交的线](https://img-blog.csdnimg.cn/2021032116363533.png)
![1035.不相交的线](https://code-thinking-1253855093.file.myqcloud.com/pics/2021032116363533.png)
## 思路

View File

@ -115,7 +115,7 @@ for (int i = 0; i < stones.size(); i++) { // 遍历物品
举例,输入:[2,4,1,1]此时target = (2 + 4 + 1 + 1)/2 = 4 dp数组状态图如下
![1049.最后一块石头的重量II](https://img-blog.csdnimg.cn/20210121115805904.jpg)
![1049.最后一块石头的重量II](https://code-thinking-1253855093.file.myqcloud.com/pics/20210121115805904.jpg)
最后dp[target]里是容量为target的背包所能背的最大重量。

View File

@ -91,7 +91,7 @@ vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
从递推公式可以看出有三个方向可以推出dp[i][j],如图:
![1143.最长公共子序列](https://img-blog.csdnimg.cn/20210204115139616.jpg)
![1143.最长公共子序列](https://code-thinking-1253855093.file.myqcloud.com/pics/20210204115139616.jpg)
那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历这个矩阵。
@ -99,7 +99,8 @@ vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));
以输入text1 = "abcde", text2 = "ace" 为例dp状态如图
![1143.最长公共子序列1](https://img-blog.csdnimg.cn/20210210150215918.jpg)
![1143.最长公共子序列1](https://code-thinking-1253855093.file.myqcloud.com/pics/20210210150215918.jpg)
最后红框dp[text1.size()][text2.size()]为最终结果

View File

@ -1,18 +1,21 @@
<p align="center">
<a href="https://programmercarl.com/other/xunlianying.html" target="_blank">
<img src="../pics/训练营.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 程序提交之后为什么会超时O(n)的算法会超时n究竟是多大
一些同学可能对计算机运行的速度还没有概念就是感觉计算机运行速度应该会很快那么在leetcode上做算法题目的时候为什么会超时呢
计算机究竟1s可以执行多少次操作呢 接下来探讨一下这个问题。
# 超时是怎么回事
![程序超时](https://img-blog.csdnimg.cn/20200729112716117.png)
![程序超时](https://code-thinking-1253855093.file.myqcloud.com/pics/20200729112716117.png)
大家在leetcode上练习算法的时候应该都遇到过一种错误是“超时”。
@ -52,6 +55,7 @@
尽管有很多因素影响,但是还是可以对自己程序的运行时间有一个大体的评估的。
引用算法4里面的一段话
* 火箭科学家需要大致知道一枚试射火箭的着陆点是在大海里还是在城市中;
* 医学研究者需要知道一次药物测试是会杀死还是会治愈实验对象;
@ -103,6 +107,7 @@ void function3(long long n) {
```
来看一下这三个函数随着n的规模变化耗时会产生多大的变化先测function1 ,就把 function2 和 function3 注释掉
```CPP
int main() {
long long n; // 数据规模
@ -126,11 +131,11 @@ int main() {
来看一下运行的效果,如下图:
![程序超时2](https://img-blog.csdnimg.cn/20200729200018460.png)
![程序超时2](https://code-thinking-1253855093.file.myqcloud.com/pics/20200729200018460.png)
O(n)的算法1s内大概计算机可以运行 5 * (10^8)次计算可以推测一下O(n^2) 的算法应该1s可以处理的数量级的规模是 5 * (10^8)开根号,实验数据如下。
![程序超时3](https://img-blog.csdnimg.cn/2020072919590970.png)
![程序超时3](https://code-thinking-1253855093.file.myqcloud.com/pics/2020072919590970.png)
O(n^2)的算法1s内大概计算机可以运行 22500次计算验证了刚刚的推测。
@ -138,7 +143,7 @@ O(n^2)的算法1s内大概计算机可以运行 22500次计算验证了刚
理论上应该是比 O(n)少一个数量级因为logn的复杂度 其实是很快,看一下实验数据。
![程序超时4](https://img-blog.csdnimg.cn/20200729195729407.png)
![程序超时4](https://code-thinking-1253855093.file.myqcloud.com/pics/20200729195729407.png)
O(nlogn)的算法1s内大概计算机可以运行 2 * (10^7)次计算,符合预期。
@ -146,7 +151,7 @@ O(nlogn)的算法1s内大概计算机可以运行 2 * (10^7)次计算,符
**整体测试数据整理如下:**
![程序超时1](https://img-blog.csdnimg.cn/20201208231559175.png)
![程序超时1](https://code-thinking-1253855093.file.myqcloud.com/pics/20201208231559175.png)
至于O(log n)和O(n^3) 等等这些时间复杂度在1s内可以处理的多大的数据规模大家可以自己写一写代码去测一下了。

Some files were not shown because too many files have changed in this diff Show More