From 1d4187b8c7eec98c4491b8b6ab88ed9b9f2fe037 Mon Sep 17 00:00:00 2001
From: baici1 <249337001@qq.com>
Date: Thu, 16 Sep 2021 19:46:14 +0800
Subject: [PATCH 1/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A037.=E8=A7=A3=E6=95=B0?=
=?UTF-8?q?=E7=8B=AC=EF=BC=8Cgo=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
problems/0037.解数独.md | 55 ++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/problems/0037.解数独.md b/problems/0037.解数独.md
index b6fa0d6e..48e1f2f2 100644
--- a/problems/0037.解数独.md
+++ b/problems/0037.解数独.md
@@ -376,6 +376,61 @@ class Solution:
Go:
+```go
+func solveSudoku(board [][]byte) {
+ var backtracking func(board [][]byte) bool
+ backtracking=func(board [][]byte) bool{
+ for i:=0;i<9;i++{
+ for j:=0;j<9;j++{
+ //判断此位置是否适合填数字
+ if board[i][j]!='.'{
+ continue
+ }
+ //尝试填1-9
+ for k:='1';k<='9';k++{
+ if isvalid(i,j,byte(k),board)==true{//如果满足要求就填
+ board[i][j]=byte(k)
+ if backtracking(board)==true{
+ return true
+ }
+ board[i][j]='.'
+ }
+ }
+ return false
+ }
+ }
+ return true
+ }
+ backtracking(board)
+}
+//判断填入数字是否满足要求
+func isvalid(row,col int,k byte,board [][]byte)bool{
+ for i:=0;i<9;i++{//行
+ if board[row][i]==k{
+ return false
+ }
+ }
+ for i:=0;i<9;i++{//列
+ if board[i][col]==k{
+ return false
+ }
+ }
+ //方格
+ startrow:=(row/3)*3
+ startcol:=(col/3)*3
+ for i:=startrow;i
+
+
1. [关于贪心算法,你该了解这些!](./problems/贪心算法理论基础.md)
2. [贪心算法:分发饼干](./problems/0455.分发饼干.md)
diff --git a/problems/0017.电话号码的字母组合.md b/problems/0017.电话号码的字母组合.md
index dfd0e875..9854ccdc 100644
--- a/problems/0017.电话号码的字母组合.md
+++ b/problems/0017.电话号码的字母组合.md
@@ -29,7 +29,7 @@
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环.......
-大家应该感觉出和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
+大家应该感觉出和[77.组合](https://programmercarl.com/0077.组合.html)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
理解本题后,要解决如下三个问题:
@@ -75,7 +75,7 @@ const string letterMap[10] = {
再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。
-注意这个index可不是 [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)中的startIndex了。
+注意这个index可不是 [77.组合](https://programmercarl.com/0077.组合.html)和[216.组合总和III](https://programmercarl.com/0216.组合总和III.html)中的startIndex了。
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
@@ -110,7 +110,7 @@ if (index == digits.size()) {
然后for循环来处理这个字符集,代码如下:
-```
+```CPP
int digit = digits[index] - '0'; // 将index指向的数字转为int
string letters = letterMap[digit]; // 取数字对应的字符集
for (int i = 0; i < letters.size(); i++) {
@@ -137,7 +137,7 @@ for (int i = 0; i < letters.size(); i++) {
关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://programmercarl.com/回溯算法理论基础.html)中的回溯法模板,不难写出如下C++代码:
-```c++
+```CPP
// 版本一
class Solution {
private:
@@ -183,7 +183,7 @@ public:
一些写法,是把回溯的过程放在递归函数里了,例如如下代码,我可以写成这样:(注意注释中不一样的地方)
-```c++
+```CPP
// 版本二
class Solution {
private:
@@ -236,10 +236,10 @@ public:
-## 其他语言版本
+# 其他语言版本
-Java:
+## Java
```Java
class Solution {
@@ -281,7 +281,7 @@ class Solution {
}
```
-Python:
+## Python
```Python
class Solution:
@@ -340,10 +340,9 @@ class Solution:
```
-Go:
+## Go
-
-> 主要在于递归中传递下一个数字
+主要在于递归中传递下一个数字
```go
func letterCombinations(digits string) []string {
@@ -382,7 +381,7 @@ func recursion(tempString ,digits string, Index int,digitsMap [10]string, res *[
}
```
-javaScript:
+## javaScript
```js
var letterCombinations = function(digits) {
diff --git a/problems/0037.解数独.md b/problems/0037.解数独.md
index b6fa0d6e..c946e838 100644
--- a/problems/0037.解数独.md
+++ b/problems/0037.解数独.md
@@ -432,6 +432,70 @@ var solveSudoku = function(board) {
};
```
+C:
+
+```C
+bool isValid(char** board, int row, int col, int k) {
+ /* 判断当前行是否有重复元素 */
+ for (int i = 0; i < 9; i++) {
+ if (board[i][col] == k) {
+ return false;
+ }
+ }
+ /* 判断当前列是否有重复元素 */
+ for (int j = 0; j < 9; j++) {
+ if (board[row][j] == k) {
+ return false;
+ }
+ }
+ /* 计算当前9宫格左上角的位置 */
+ int startRow = (row / 3) * 3;
+ int startCol = (col / 3) * 3;
+ /* 判断当前元素所在九宫格是否有重复元素 */
+ for (int i = startRow; i < startRow + 3; i++) {
+ for (int j = startCol; j < startCol + 3; j++) {
+ if (board[i][j] == k) {
+ return false;
+ }
+ }
+ }
+ /* 满足条件,返回true */
+ return true;
+}
+
+bool backtracking(char** board, int boardSize, int* boardColSize) {
+ /* 从上到下、从左到右依次遍历输入数组 */
+ for (int i = 0; i < boardSize; i++) {
+ for (int j = 0; j < *boardColSize; j++) {
+ /* 遇到数字跳过 */
+ if (board[i][j] != '.') {
+ continue;
+ }
+ /* 依次将数组1到9填入当前位置 */
+ for (int k = '1'; k <= '9'; k++) {
+ /* 判断当前位置是否与满足条件,是则进入下一层 */
+ if (isValid(board, i, j, k)) {
+ board[i][j] = k;
+ /* 判断下一层递归之后是否找到一种解法,是则返回true */
+ if (backtracking(board, boardSize, boardColSize)) {
+ return true;
+ }
+ /* 回溯,将当前位置清零 */
+ board[i][j] = '.';
+ }
+ }
+ /* 若填入的9个数均不满足条件,返回false,说明此解法无效 */
+ return false;
+ }
+ }
+ /* 遍历完所有的棋盘,没有返回false,说明找到了解法,返回true */
+ return true;
+}
+
+void solveSudoku(char** board, int boardSize, int* boardColSize) {
+ bool res = backtracking(board, boardSize, boardColSize);
+}
+```
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md
index 01706eb3..c5de73c7 100644
--- a/problems/0047.全排列II.md
+++ b/problems/0047.全排列II.md
@@ -33,11 +33,11 @@
**如果对回溯算法基础还不了解的话,我还特意录制了一期视频:[带你学透回溯算法(理论篇)](https://www.bilibili.com/video/BV1cy4y167mM/)** 可以结合题解和视频一起看,希望对大家理解回溯算法有所帮助。
-这道题目和[回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html)的区别在与**给定一个可包含重复数字的序列**,要返回**所有不重复的全排列**。
+这道题目和[46.全排列](https://programmercarl.com/0046.全排列.html)的区别在与**给定一个可包含重复数字的序列**,要返回**所有不重复的全排列**。
这里又涉及到去重了。
-在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html) 、[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)我们分别详细讲解了组合问题和子集问题如何去重。
+在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html) 、[90.子集II](https://programmercarl.com/0090.子集II.html)我们分别详细讲解了组合问题和子集问题如何去重。
那么排列问题其实也是一样的套路。
@@ -51,11 +51,11 @@
**一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果**。
-在[回溯算法:排列问题!](https://programmercarl.com/0046.全排列.html)中已经详解讲解了排列问题的写法,在[回溯算法:求组合总和(三)](https://programmercarl.com/0040.组合总和II.html) 、[回溯算法:求子集问题(二)](https://programmercarl.com/0090.子集II.html)中详细讲解的去重的写法,所以这次我就不用回溯三部曲分析了,直接给出代码,如下:
+在[46.全排列](https://programmercarl.com/0046.全排列.html)中已经详解讲解了排列问题的写法,在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html) 、[90.子集II](https://programmercarl.com/0090.子集II.html)中详细讲解的去重的写法,所以这次我就不用回溯三部曲分析了,直接给出代码,如下:
## C++代码
-```
+```CPP
class Solution {
private:
vector
> result = new ArrayList<>();
@@ -369,7 +369,25 @@ class Solution {
```
-Python:
+## Python
+```python
+class Solution:
+ def combine(self, n: int, k: int) -> List[List[int]]:
+ res = []
+ path = []
+ def backtrack(n, k, StartIndex):
+ if len(path) == k:
+ res.append(path[:])
+ return
+ for i in range(StartIndex, n-(k-len(path)) + 2):
+ path.append(i)
+ backtrack(n, k, i+1)
+ path.pop()
+ backtrack(n, k, 1)
+ return res
+```
+
+剪枝:
```python3
class Solution:
def combine(self, n: int, k: int) -> List[List[int]]:
@@ -378,15 +396,19 @@ class Solution:
def backtrack(n,k,startIndex):
if len(path) == k:
res.append(path[:])
- return
- for i in range(startIndex,n+1):
+ return
+ for i in range(startIndex,n-(k-len(path))+2): #优化的地方
path.append(i) #处理节点
backtrack(n,k,i+1) #递归
path.pop() #回溯,撤销处理的节点
- backtrack(n,k,1)
- return res
+ backtrack(n,k,1)
+ return res
```
-javascript
+
+
+## javascript
+
+剪枝:
```javascript
let result = []
let path = []
@@ -406,8 +428,11 @@ const combineHelper = (n, k, startIndex) => {
path.pop()
}
}
-```
-Go:
+```
+
+
+
+## Go
```Go
var res [][]int
func combine(n int, k int) [][]int {
@@ -434,8 +459,35 @@ func backtrack(n,k,start int,track []int){
}
}
```
+剪枝:
+```Go
+var res [][]int
+func combine(n int, k int) [][]int {
+ res=[][]int{}
+ if n <= 0 || k <= 0 || k > n {
+ return res
+ }
+ backtrack(n, k, 1, []int{})
+ return res
+}
+func backtrack(n,k,start int,track []int){
+ if len(track)==k{
+ temp:=make([]int,k)
+ copy(temp,track)
+ res=append(res,temp)
+ }
+ if len(track)+n-start+1 < k {
+ return
+ }
+ for i:=start;i<=n;i++{
+ track=append(track,i)
+ backtrack(n,k,i+1,track)
+ track=track[:len(track)-1]
+ }
+}
+```
-C:
+## C
```c
int* path;
int pathTop;
@@ -489,6 +541,60 @@ int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
}
```
+剪枝:
+```c
+int* path;
+int pathTop;
+int** ans;
+int ansTop;
+
+void backtracking(int n, int k,int startIndex) {
+ //当path中元素个数为k个时,我们需要将path数组放入ans二维数组中
+ if(pathTop == k) {
+ //path数组为我们动态申请,若直接将其地址放入二维数组,path数组中的值会随着我们回溯而逐渐变化
+ //因此创建新的数组存储path中的值
+ int* temp = (int*)malloc(sizeof(int) * k);
+ int i;
+ for(i = 0; i < k; i++) {
+ temp[i] = path[i];
+ }
+ ans[ansTop++] = temp;
+ return ;
+ }
+
+ int j;
+ for(j = startIndex; j <= n- (k - pathTop) + 1;j++) {
+ //将当前结点放入path数组
+ path[pathTop++] = j;
+ //进行递归
+ backtracking(n, k, j + 1);
+ //进行回溯,将数组最上层结点弹出
+ pathTop--;
+ }
+}
+
+int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
+ //path数组存储符合条件的结果
+ path = (int*)malloc(sizeof(int) * k);
+ //ans二维数组存储符合条件的结果数组的集合。(数组足够大,避免极端情况)
+ ans = (int**)malloc(sizeof(int*) * 10000);
+ pathTop = ansTop = 0;
+
+ //回溯算法
+ backtracking(n, k, 1);
+ //最后的返回大小为ans数组大小
+ *returnSize = ansTop;
+ //returnColumnSizes数组存储ans二维数组对应下标中一维数组的长度(都为k)
+ *returnColumnSizes = (int*)malloc(sizeof(int) *(*returnSize));
+ int i;
+ for(i = 0; i < *returnSize; i++) {
+ (*returnColumnSizes)[i] = k;
+ }
+ //返回ans二维数组
+ return ans;
+}
+```
+
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
diff --git a/problems/0078.子集.md b/problems/0078.子集.md
index 583fe664..fb4a8740 100644
--- a/problems/0078.子集.md
+++ b/problems/0078.子集.md
@@ -31,7 +31,7 @@
## 思路
-求子集问题和[回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)和[回溯算法:分割问题!](https://programmercarl.com/0131.分割回文串.html)又不一样了。
+求子集问题和[77.组合](https://programmercarl.com/0077.组合.html)和[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)又不一样了。
如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,**那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!**
@@ -157,7 +157,7 @@ public:
相信大家经过了
* 组合问题:
- * [回溯算法:求组合问题!](https://programmercarl.com/0077.组合.html)
+ * [回溯算法:求组合问题](https://programmercarl.com/0077.组合.html)
* [回溯算法:组合问题再剪剪枝](https://programmercarl.com/0077.组合优化.html)
* [回溯算法:求组合总和!](https://programmercarl.com/0216.组合总和III.html)
* [回溯算法:电话号码的字母组合](https://programmercarl.com/0017.电话号码的字母组合.html)
diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md
index 6dc631de..c8cb42d3 100644
--- a/problems/0090.子集II.md
+++ b/problems/0090.子集II.md
@@ -32,7 +32,7 @@
做本题之前一定要先做[78.子集](https://programmercarl.com/0078.子集.html)。
-这道题目和[回溯算法:求子集问题!](https://programmercarl.com/0078.子集.html)区别就是集合里有重复元素了,而且求取的子集要去重。
+这道题目和[78.子集](https://programmercarl.com/0078.子集.html)区别就是集合里有重复元素了,而且求取的子集要去重。
那么关于回溯算法中的去重问题,**在[40.组合总和II](https://programmercarl.com/0040.组合总和II.html)中已经详细讲解过了,和本题是一个套路**。
diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md
index 9f2ea6e7..6d01319a 100644
--- a/problems/0093.复原IP地址.md
+++ b/problems/0093.复原IP地址.md
@@ -45,11 +45,11 @@ s 仅由数字组成
## 思路
-做这道题目之前,最好先把[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。
+做这道题目之前,最好先把[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)这个做了。
这道题目相信大家刚看的时候,应该会一脸茫然。
-其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)就十分类似了。
+其实只要意识到这是切割问题,**切割问题就可以使用回溯搜索法把所有可能性搜出来**,和刚做过的[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)就十分类似了。
切割问题可以抽象为树型结构,如图:
@@ -60,7 +60,7 @@ s 仅由数字组成
* 递归参数
-在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我们就提到切割问题类似组合问题。
+在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中我们就提到切割问题类似组合问题。
startIndex一定是需要的,因为不能重复分割,记录下一层递归分割的起始位置。
@@ -76,7 +76,7 @@ startIndex一定是需要的,因为不能重复分割,记录下一层递归
* 递归终止条件
-终止条件和[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
+终止条件和[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)情况就不同了,本题明确要求只会分成4段,所以不能用切割线切到最后作为终止条件,而是分割的段数作为终止条件。
pointNum表示逗点数量,pointNum为3说明字符串分成了4段了。
@@ -96,7 +96,7 @@ if (pointNum == 3) { // 逗点数量为3时,分隔结束
* 单层搜索的逻辑
-在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中已经讲过在循环遍历中如何截取子串。
+在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中已经讲过在循环遍历中如何截取子串。
在`for (int i = startIndex; i < s.size(); i++)`循环中 [startIndex, i]这个区间就是截取的子串,需要判断这个子串是否合法。
@@ -239,11 +239,11 @@ public:
## 总结
-在[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。
+在[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)中我列举的分割字符串的难点,本题都覆盖了。
而且本题还需要操作字符串添加逗号作为分隔符,并验证区间的合法性。
-可以说是[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html)的加强版。
+可以说是[131.分割回文串](https://programmercarl.com/0131.分割回文串.html)的加强版。
在本文的树形结构图中,我已经把详细的分析思路都画了出来,相信大家看了之后一定会思路清晰不少!
diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md
index ac43f0a5..4b0908fd 100644
--- a/problems/0102.二叉树的层序遍历.md
+++ b/problems/0102.二叉树的层序遍历.md
@@ -6,6 +6,7 @@
欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+# 二叉树层序遍历登场! 学会二叉树的层序遍历,可以一口气打完以下十题: @@ -20,7 +21,6 @@ * 104.二叉树的最大深度 * 111.二叉树的最小深度 -在之前写过这篇文章 [二叉树:层序遍历登场!](https://programmercarl.com/0102.二叉树的层序遍历.html),可惜当时只打了5个,还不够,再给我一次机会,我打十个!  diff --git a/problems/0122.买卖股票的最佳时机II.md b/problems/0122.买卖股票的最佳时机II.md index bd837eea..4bbe9e5e 100644 --- a/problems/0122.买卖股票的最佳时机II.md +++ b/problems/0122.买卖股票的最佳时机II.md @@ -131,9 +131,9 @@ public: 一旦想到这里了,很自然就会想到贪心了,即:只收集每天的正利润,最后稳稳的就是最大利润了。 -## 其他语言版本 +# 其他语言版本 -Java: +## Java ```java // 贪心思路 @@ -171,7 +171,7 @@ class Solution { // 动态规划 -Python: +## Python ```python class Solution: def maxProfit(self, prices: List[int]) -> int: @@ -181,7 +181,21 @@ class Solution: return result ``` -Go: +python动态规划 +```python +class Solution: + def maxProfit(self, prices: List[int]) -> int: + length = len(prices) + dp = [[0] * 2 for _ in range(length)] + dp[0][0] = -prices[0] + dp[0][1] = 0 + for i in range(1, length): + dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) #注意这里是和121. 买卖股票的最佳时机唯一不同的地方 + dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]) + return dp[-1][1] +``` + +## Go ```golang //贪心算法 func maxProfit(prices []int) int { @@ -217,9 +231,9 @@ func maxProfit(prices []int) int { } ``` -Javascript: +## Javascript +贪心 ```Javascript -// 贪心 var maxProfit = function(prices) { let result = 0 for(let i = 1; i < prices.length; i++) { @@ -229,7 +243,31 @@ var maxProfit = function(prices) { }; ``` -C: +动态规划 +```javascript +const maxProfit = (prices) => { + let dp = Array.from(Array(prices.length), () => Array(2).fill(0)); + // dp[i][0] 表示第i天持有股票所得现金。 + // dp[i][1] 表示第i天不持有股票所得最多现金 + dp[0][0] = 0 - prices[0]; + dp[0][1] = 0; + for(let i = 1; i < prices.length; i++) { + // 如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来 + // 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0] + // 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i] + dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i]); + + // 在来看看如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来 + // 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1] + // 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0] + dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]); + } + + return dp[prices.length -1][0]; +}; +``` + +## C ```c int maxProfit(int* prices, int pricesSize){ int result = 0; diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 177c6b03..f75105f0 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -30,7 +30,7 @@ 输出: [[1,2,6], [1,3,5], [2,3,4]] -## 思路 +# 思路 本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。 @@ -180,7 +180,7 @@ if (sum > targetSum) { // 剪枝操作 最后C++代码如下: -```c++ +```CPP class Solution { private: vector欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!
+ + +# 力扣上如何自己构造二叉树输入用例? + +经常有录友问,二叉树的题目中输入用例在ACM模式下应该怎么构造呢? + +力扣上的题目,输入用例就给了一个数组,怎么就能构造成二叉树呢? + +这次就给大家好好讲一讲! + +就拿最近公众号上 二叉树的打卡题目来说: + +[538.把二叉搜索树转换为累加树](https://mp.weixin.qq.com/s/rlJUFGCnXsIMX0Lg-fRpIw) + +其输入用例,就是用一个数组来表述 二叉树,如下: + + + +一直跟着公众号学算法的录友 应该知道,我在[二叉树:构造二叉树登场!](https://mp.weixin.qq.com/s/Dza-fqjTyGrsRw4PWNKdxA),已经讲过,**只有 中序与后序 和 中序和前序 可以确定一颗唯一的二叉树。 前序和后序是不能确定唯一的二叉树的**。 + +那么[538.把二叉搜索树转换为累加树](https://mp.weixin.qq.com/s/rlJUFGCnXsIMX0Lg-fRpIw)的示例中,为什么,一个序列(数组或者是字符串)就可以确定二叉树了呢? + +很明显,是后台直接明确了构造规则。 + +再看一下 这个 输入序列 和 对应的二叉树。 + + +从二叉树 推导到 序列,大家可以发现这就是层序遍历。 + +但从序列 推导到 二叉树,很多同学就看不懂了,这得怎么转换呢。 + +我在 [关于二叉树,你该了解这些!](https://mp.weixin.qq.com/s/q_eKfL8vmSbSFcptZ3aeRA)已经详细讲过,二叉树可以有两种存储方式,一种是 链式存储,另一种是顺序存储。 + +链式存储,就是大家熟悉的二叉树,用指针指向左右孩子。 + +顺序存储,就是用一个数组来存二叉树,其方式如图所示: + + + +那么此时大家是不是应该知道了,数组如何转化成 二叉树了。**如果父节点的数组下标是i,那么它的左孩子下标就是i * 2 + 1,右孩子下标就是 i * 2 + 2**。 + +那么这里又有同学疑惑了,这些我都懂了,但我还是不知道 应该 怎么构造。 + +来,咱上代码。 昨天晚上 速度敲了一遍实现代码。 + +具体过程看注释: + +```CPP +// 根据数组构造二叉树 +TreeNode* construct_binary_tree(const vector