二叉树的深度为根节点到最远叶子节点的最长路径上的节点数,叶子节点是指没有子节点的节点。
示例:
给定二叉树[3,9,20,null,null,15,7],
3/ \9 20/ \15 7
返回它的最大深度 3。
解法一:递归遍历二叉树,回溯算法思路
遍历一遍二叉树,用一个外部变量记录每个节点所在的深度,取最大值就可以得到最大深度。
class Solution {
public:int depth = 0;int res = 0;int maxDepth(TreeNode* root) {traverse(root);return res;}//遍历二叉树void traverse(TreeNode* root){if(root == nullptr){return;}//前序遍历位置depth++;//遍历过程中记录最大深度res = max(depth, res);traverse(root->left);traverse(root->right);//后序遍历位置depth--;}
};
解法二:分解成子树问题,动态规划思路
class Solution {
public:// 定义:输入一个节点,返回以该节点为根的二叉树的最大深度int maxDepth(TreeNode* root) {if(root == nullptr){return 0;}int leftDepth = maxDepth(root->left);int rightDepth = maxDepth(root->right);// 根据左右子树的最大深度推出原二叉树的最大深度return max(leftDepth, rightDepth) + 1;}
};
解法三:层序遍历
class Solution {
public:int maxDepth(TreeNode* root) {int depth = 0;queue que;if(root) que.push(root);while(!que.empty()){int size = que.size();depth++;for(int i = 0; i < size; i++){TreeNode* node = que.front();que.pop();if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return depth;}
};
求二叉树的最大深度可以延伸到求二叉树的直径:
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 :
给定二叉树
1/ \2 3/ \ 4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
每一条二叉树的「直径」长度,就是一个节点的左右子树的最大深度之和。把计算「直径」的逻辑放在后序位置,准确说应该是放在 maxDepth 的后序位置,因为 maxDepth 的后序位置是知道左右子树的最大深度的。
class Solution {
public:int maxDiameter = 0;int diameterOfBinaryTree(TreeNode* root) {maxDepth(root);return maxDiameter; }//定义:输入一个节点,返回以该节点为根节点的二叉树的深度int maxDepth(TreeNode* root){if(root == nullptr){return 0;}int leftDepth = maxDepth(root->left);int rightDepth = maxDepth(root->right);// 后序位置,顺便计算最大直径maxDiameter = max(leftDepth + rightDepth, maxDiameter);return max(leftDepth, rightDepth) + 1;}
};
给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
示例:给定二叉树[3,9,20,null,null,15,7]:
3/ \9 20/ \ 15 7
返回它的最小深度2。
解法一:分解成子树问题,动态规划思想
class Solution {
public://定义:输入一个节点,返回以该节点为根节点的二叉树的最小深度int minDepth(TreeNode* root) {if(!root) {return 0;}int leftDepth = minDepth(root->left);int rightDepth = minDepth(root->right);return min(leftDepth, rightDepth) + 1; }
};
❓上面的算法对吗?为什么?
❎错误!
✅正确的解法一:分解成子树问题,动态规划思想
class Solution {
public:int minDepth(TreeNode* root) {if(!root){return 0;}int leftDepth = minDepth(root->left);int rightDepth = minDepth(root->right);if(!root->left){return rightDepth + 1;}if(!root->right){return leftDepth + 1;}return min(leftDepth, rightDepth) + 1;}
};
解法二:层序遍历
class Solution {
public:int minDepth(TreeNode* root) {int depth = 0;queue que;if(root) que.push(root);while(!que.empty()){int size = que.size();depth++;for(int i = 0; i < size; i++){TreeNode* node = que.front();que.pop();if(!node->left && !node->right) return depth;if(node->left) que.push(node->left);if(node->right) que.push(node->right);}}return depth;}
};
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例 :

输入:root = [3,9,20,null,null,15,7]
输出:true
本题依然是二叉树深度相关的题目,依然是把计算「高度差」的逻辑放在后序位置,准确说应该是放在 maxDepth 的后序位置,因为 maxDepth 的后序位置是知道左右子树的最大深度的。
只计算一次最大深度,计算的过程中在后序遍历位置顺便判断二叉树是否平衡:对于每个节点,先算出来左右子树的最大高度,然后在后序遍历的位置根据左右子树的最大高度判断平衡性。
class Solution {
public:// 记录二叉树是否平衡bool balance = true;bool isBalanced(TreeNode* root) {maxDepth(root);return balance;}// 定义:输入一个节点,返回以该节点为根的二叉树的最大深度int maxDepth(TreeNode* root){if(!root) return 0;int leftDepth= maxDepth(root->left);int rightDepth = maxDepth(root->right);if(abs(leftDepth - rightDepth) > 1) balance = false;return max(leftDepth, rightDepth) + 1;}
};
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
解法一:递归遍历,回溯算法的思想
遍历二叉树的每个节点,每个节点的左、右子树交换位置。
class Solution {
public:TreeNode* invertTree(TreeNode* root) {traverse(root);return root;}// 二叉树遍历函数void traverse(TreeNode* root){if(!root){return;}// 每一个节点需要做的事就是交换它的左右子节点TreeNode* tmp = root->left;root->left = root->right;root->right = tmp;// 遍历框架,去遍历左右子树的节点traverse(root->left);traverse(root->right);}
};
解法二:分解为子树的问题,动态规划思想
用 invertTree(x.left) 先把 x 的左子树翻转,再用 invertTree(x.right) 把 x 的右子树翻转,最后把 x 的左右子树交换,这恰好完成了以 x 为根的整棵二叉树的翻转,即完成了 invertTree(x) 的定义。
class Solution {
public://定义:输入一个节点,将以该节点为根节点的二叉树进行翻转,返回其根节点TreeNode* invertTree(TreeNode* root) {if(!root) {return root;}// 利用函数定义,先翻转左右子树TreeNode* left = invertTree(root->left);TreeNode* right = invertTree(root->right);// 然后交换左右子节点root->left = right;root->right = left;return root;}
};
解法三:层序遍历
class Solution {
public:TreeNode* invertTree(TreeNode* root) {if (root == NULL) return root;stack st;st.push(root);while(!st.empty()) {TreeNode* node = st.top(); // 中st.pop();swap(node->left, node->right);if(node->right) st.push(node->right); // 右if(node->left) st.push(node->left); // 左}return root;}
};
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
示例:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
解法一:递归遍历,回溯算法思想
前部遍历位置(进入节点)sum += root->val,顺便判断是否到达叶子节点且和为targetSum;后序遍历位置(离开节点)sum -= root->val。
class Solution {
public:bool res = false;int sum = 0;bool hasPathSum(TreeNode* root, int targetSum) {traverse(root, targetSum);return res;}void traverse(TreeNode* root, int targetSum){if(!root) return;//前序遍历位置sum += root->val;// 到达叶子节点且和为targetSumif(!root->left && !root->right && sum == targetSum) res = true;traverse(root->left, targetSum);traverse(root->right, targetSum);//后序遍历位置sum -= root->val;}
};
解法二:分解成子树问题,动态规划思想
遍历到一个节点,继续遍历左孩子和右孩子,且targetSum减去节点的数值。
class Solution {public:// 定义:输入一个根节点,返回该根节点到叶子节点是否存在一条和为 targetSum 的路径bool hasPathSum(TreeNode* root, int targetSum) {if(!root) return false;if(!root->left && !root->right && root->val == targetSum) return true;// 左子树或者右子树有一个满足即可return hasPathSum(root->left, targetSum - root->val) ||hasPathSum(root->right, targetSum - root->val);}
};
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
示例:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
相对于⌈112、路径总和⌋来说,前序和后序位置不仅要维护sum,还要维护路径path。
class Solution {
public:vector> res;vector path;int sum = 0;vector> pathSum(TreeNode* root, int targetSum) {traverse(root, targetSum);return res;}void traverse(TreeNode* root, int targetSum){if(!root) return;//前序遍历位置sum += root->val;path.push_back(root->val);if(!root->left && !root->right && sum == targetSum) res.push_back(path);traverse(root->left, targetSum);traverse(root->right, targetSum);//后序遍历位置sum -= root->val;path.pop_back();}
};
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例:

输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示
这题及要求你准确理解二叉树的前序后序遍历,还要熟悉前缀和技巧,把前缀和技巧用到二叉树上。
这道题涉及到数组的技巧,暂定先不做。
101、对称二叉树和100、相同的树结合起来看,两道题方法和代码上非常相似。
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例:
输入:p = [1,2,3], q = [1,2,3]
输出:true
解法一:分解成子树问题
class Solution {
public:bool isSameTree(TreeNode* p, TreeNode* q) {if(!p || !q) return p == q;if(p->val != q->val) return false;bool left = isSameTree(p->left, q->left); //比较左子树bool right = isSameTree(p->right, q->right);//比较右子树return left && right;}
};
代码简化为:
class Solution {
public:bool isSameTree(TreeNode* p, TreeNode* q) {// 判断一对节点是否相同if(!p || !q) return p == q;if(p->val != q->val) return false;// 判断其他节点是否相同return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);}
};
解法二:迭代法
class Solution {
public:bool isSameTree(TreeNode* p, TreeNode* q) {queue que;que.push(p);que.push(q);//注意不能加上写成如下代码,否则会报错//if(p) que.push(p); //if(q) que.push(q); while (!que.empty()) { // 接下来就要判断这两颗树是否相等TreeNode* leftNode = que.front(); que.pop();TreeNode* rightNode = que.front(); que.pop();if (!leftNode && !rightNode) { // 左节点为空、右节点为空,此时说明是相等的continue;}// 左右一个节点不为空,或者都不为空但数值不相同,返回falseif ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {return false;}que.push(leftNode->left); que.push(rightNode->left); que.push(leftNode->right); que.push(rightNode->right); }return true;}
};
注意:
que.push(p);
que.push(q);
不能写为:
if(p) que.push(p);
if(q) que.push(q);
否则会报错:
执行出错信息:
Line 15: Char 74: runtime error: member access within misaligned address 0xbebebebebebebebe for type 'TreeNode', which requires 8 byte alignment (solution.cpp)
0xbebebebebebebebe: note: pointer points here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:24:74
最后执行的输入:
[]
[0]
加上if判断后,若输入当中有为空的,则无法加入到队列当中,影响后序的代码逻辑运行。
给定一个二叉树,检查它是否是镜像对称的。
解法一:分解成子树问题
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两颗树(这两颗树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。
正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中,只有内侧和外侧节点分别对应相等,这两棵树才是对称的。
返回条件:
代码如下:
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false;
class Solution {
public:bool isSymmetric(TreeNode* root) {if(!root) return true;return compare(root->left, root->right);}//定义:输入左、右节点,返回分别以这两节点为根节点的二叉树是否对称bool compare(TreeNode* left, TreeNode* right){// 注意这里终止条件的代码if(!left || !right) return left == right;if(left->val != right->val) return false;bool outside = compare(left->left, right->right); //外侧节点比较bool inside = compare(left->right, right->left); //内侧节点比较return outside && inside; //左右子节点需要对称相同}
};
代码简化为:
class Solution {
public:bool isSymmetric(TreeNode* root) {if(!root) return true;return compare(root->left, root->right);}//定义:输入左、右节点,返回分别以这两节点为根节点的二叉树是否对称bool compare(TreeNode* left, TreeNode* right){// 该对节点是否对称if(!left || !right) return left == right;if(left->val != right->val) return false;// 其他节点是否对称return compare(left->left, right->right) && compare(left->right, right->left);}
};
解法二:迭代法,不是层序遍历,这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转。
把左右两个子树要比较的元素顺序放进一个容器,然后成对的取出来进行比较,那么其实使用栈也是可以的。
class Solution {
public:bool isSymmetric(TreeNode* root) {if (root == NULL) return true;queue que;que.push(root->left); // 将左子树头结点加入队列que.push(root->right); // 将右子树头结点加入队列while (!que.empty()) { // 接下来就要判断这两个树是否相互翻转TreeNode* leftNode = que.front(); que.pop();TreeNode* rightNode = que.front(); que.pop();if (!leftNode && !rightNode) { // 左节点为空、右节点为空,此时说明是对称的continue;}// 左右一个节点不为空,或者都不为空但数值不相同,返回falseif ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {return false;}que.push(leftNode->left); // 加入左节点左孩子que.push(rightNode->right); // 加入右节点右孩子que.push(leftNode->right); // 加入左节点右孩子que.push(rightNode->left); // 加入右节点左孩子}return true;}
};
给你两棵二叉树 root 和 subRoot ,检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点,tree 也可以看做它自身的一棵子树。
示例:
输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
遍历以 root 为根的这棵二叉树的所有节点,用 ⌈100、相同的树⌋ 中的 isSameTree 函数判断以该节点为根的子树是否和以 subRoot 为根的那棵树相同。
class Solution {
public:bool isSubtree(TreeNode* root, TreeNode* subRoot) {if(!root) return root == subRoot;// 判断以 root 为根的二叉树是否和 subRoot 相同if(isSameTree(root, subRoot)) return true;// 去左右子树中判断是否有和 subRoot 相同的子树return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);}// 定义:输入两个节点,判断以两个节点为根节点的二叉树是否一样,返回结果bool isSameTree(TreeNode* p, TreeNode* q) {// 判断一对节点是否相同if(!p || !q) return p == q;if(p->val != q->val) return false;// 判断其他节点是否相同return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);}
};
给定二叉树的根节点 root ,返回所有左叶子之和。
示例:
输入: root = [3,9,20,null,null,15,7]
输出: 24
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。
本题遍历二叉树即可,问题是如何判断节点是左叶子呢?
如果左节点不为空,且左节点没有左右孩子,那么这个节点的左节点就是左叶子,必须要通过节点的父节点来判断其左孩子是不是左叶子:
if (node->left != NULL && node->left->left == NULL && node->left->right == NULL) {左叶子节点处理逻辑
}
class Solution {
public:int sum = 0;int sumOfLeftLeaves(TreeNode* root) {traverse(root);return sum;}void traverse(TreeNode* root){if(!root) return;// 找到左侧的叶子节点,记录累加值if(root->left && !root->left->left && !root->left->right){sum += root->left->val;}traverse(root->left);traverse(root->right);}
};
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例:
输入: root = [2,1,3]
输出: 1
解法一:递归遍历二叉树
二叉树递归框架代码是先递归左子树,后递归右子树,所以到最大深度时第一次遇到的节点就是左下角的节点。
class Solution {
public:int depth; // 记录 traverse 递归遍历到的深度int maxDepth; // 记录二叉树的最大深度TreeNode* res;int findBottomLeftValue(TreeNode* root) {traverse(root);return res->val;}void traverse(TreeNode* root){if(!root) return;depth++;// 到最大深度时第一次遇到的节点就是左下角的节点if(depth > maxDepth){maxDepth = depth;res = root;}traverse(root->left);traverse(root->right);depth--;}
};
解法二:层序遍历,很好理解
class Solution {
public:int findBottomLeftValue(TreeNode* root) {queue que;if (root != NULL) que.push(root);int result = 0; //后续循环会不断刷新result的值while (!que.empty()) {int size = que.size();for (int i = 0; i < size; i++) {TreeNode* node = que.front();que.pop();if (i == 0) result = node->val; // 记录最后一行第一个元素if (node->left) que.push(node->left);if (node->right) que.push(node->right);}}return result;}
};
找树左下角的值会做了,找树右下角的值自然也会做了,也就是把遍历的顺序改变一下:先遍历右子树,再遍历左子树。
给定一个二叉树,确定他是否是一个完全二叉树。
完全二叉树的定义:若二叉树的深度为 h,除第 h 层外,其它各层的结点数都达到最大个数,第 h 层所有的叶子结点都连续集中在最左边,这就是完全二叉树。(第 h 层可能包含 [1~2h] 个节点)
样例图1:叶子节点出现在最后一层
样例图2:叶子节点出现在最后一次和倒数第二层
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
本道题的解题关键就是要紧紧抓住完全二叉树的定义,使用层序遍历。如果遇到某个节点为空,进行标记,代表访问到完全二叉树的最下层,若是后续还有访问,则不符合完全二叉树的定义。
注意:
que.push(node->left);
que.push(node->right);
不能写成:
if(node->left) push(node->left);
if(node->right) que.push(node->right);
否则, 完全二叉树最后一层的空节点是访问不到的。
class Solution {public:bool isCompleteTree(TreeNode* root) {//空树一定是完全二叉树if(root == NULL) return true;queue que;if(root) que.push(root); //定义一个首次出现的标记位bool flag = false; while(!que.empty()){ int size = que.size();for (int i = 0; i < size; i++) {TreeNode* node = que.front();que.pop();//标记第一次遇到空节点if (!node) flag = true; else{//后续访问已经遇到空节点了,说明经过了叶子if (flag) return false;que.push(node->left);que.push(node->right);}}}return true;}
};
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
示例:
输入:root = [1,2,3,4,5,6]
输出:6
首先要搞清楚什么是 ⌈完全二叉树⌋ 和 ⌈满二叉树⌋ :
完全二叉树如下图,每一层都是紧凑靠左排列的,除了最底层节点可能没填满外,其余每层节点数都达到最大值:
满二叉树如下图,是一种特殊的完全二叉树,每层都是是满的,像一个稳定的三角形:
如果是一个普通二叉树,显然只要向下面这样遍历一边即可,时间复杂度 O(N):
int countNodes(TreeNode* root) {if (root == null) return 0;return 1 + countNodes(root->left) + countNodes(root->right);
}
那如果是一棵满二叉树,节点总数就和树的高度呈指数关系:
int countNodes(TreeNode* root) {int h = 0;// 计算树的高度while (root != null) {root = root->left;h++;}// 节点总数就是 2^h - 1return (2 << h) - 1;
}
完全二叉树比普通二叉树特殊,但又没有满二叉树那么特殊,计算它的节点总数,可以说是普通二叉树和完全二叉树的结合版。
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。
class Solution {
public:int countNodes(TreeNode* root) {if (!root) return 0;TreeNode* left = root->left;TreeNode* right = root->right;// 这里初始为0是有目的的,为了下面求指数方便int leftHeight = 0;int rightHeight = 0; // 记录左、右子树的高度while (left) {left = left->left;leftHeight++;}while (right) {right = right->right;rightHeight++;}// 如果左右子树的高度相同,则是一棵满二叉树if (leftHeight == rightHeight) {return (2 << leftHeight) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0}// 如果左右高度不同,则按照普通二叉树的逻辑计算return countNodes(root->left) + countNodes(root->right) + 1;}
};
这个算法的时间复杂度是 O(logN*logN),但直觉感觉好像最坏情况下是 O(N*logN) ,因为之前的 while 需要 logN 的时间,最后要 O(N) 的时间向左右子树递归:
return 1 + countNodes(root.left) + countNodes(root.right);
关键点在于,这两个递归只有一个会真的递归下去,另一个一定会触发 leftHeight == rightHeight 而立即返回,不会递归下去。
所以,算法的递归深度就是树的高度 O(logN),每次递归所花费的时间就是 while 循环,需要 O(logN),所以总体的时间复杂度是 O(logN*logN)。
给你二叉树的根结点 root ,请你将它展开为一个单链表:
TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。示例 :
输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
解法一:递归遍历
对整棵树进行前序遍历,一边遍历一边构造出一条「链表」。
class Solution {
public:// 虚拟头节点,res->right 就是结果TreeNode* res = new TreeNode(-1);// 用来构建链表的指针TreeNode* p = res;TreeNode* flatten(TreeNode* root) {traverse(root);return res->right;}void traverse(TreeNode* root){if(!root) return;p = new TreeNode(root->val);p = p->right;traverse(root->left);traverse(root->right);}
};
但是注意 flatten 函数的签名,返回类型为 void,也就是说题目希望我们在原地把二叉树拉平成链表。
这样一来,没办法通过简单的二叉树遍历来解决这道题了。
解法二:分解成子树的问题
对于一个节点 x,可以执行以下流程:
1、先利用 flatten(x.left) 和 flatten(x.right) 将 x 的左右子树拉平。
2、将 x 的右子树接到左子树下方,然后将整个左子树作为右子树。
这样,以 x 为根的整棵二叉树就被拉平了,恰好完成了 flatten(x) 的定义。
class Solution {
public://定义:输入一个节点,将以该节点为根节点的二叉树展开成单链表void flatten(TreeNode* root) {if(!root) return;// 利用定义,把左右子树拉平flatten(root->left);flatten(root->right);// 1、左右子树已经被拉平成一条链表TreeNode* left = root->left;TreeNode* right = root->right;// 2、将左子树作为右子树root->left = nullptr;root->right = left;// 3、将原先的右子树接到当前右子树的末端TreeNode* p = root;// 注意这里的条件是 p->right,而不是 p ,即有右孩子则移动指针while(p->right){p = p->right;}p->right = right;}
};
下一篇:PTA题目 阶梯电价