二叉树刷题 (2)
左子叶之和 404
左叶子的定义:某节点的左节点不为空且该节点的左节点无左孩子右孩子
使用前序遍历。
递归三部曲:
1.确定返回值及函数参数:
求一棵树的左节点之和,输入根节点,返回int
2.确定中止条件:
if(root == nullptr) return 0;
3.确定单层递归逻辑:
int leftValue = sumOfLeftLeaves(root->left); // 左
if (root->left && !root->left->left && !root->left->right) {
leftValue = root->left->val;
}
int rightValue = sumOfLeftLeaves(root->right); // 右
int sum = leftValue + rightValue; // 中
return sum;
整体C++代码:
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right== NULL) return 0;
int leftValue = sumOfLeftLeaves(root->left); // 左
if (root->left && !root->left->left && !root->left->right) { // 左子树就是一个左叶子的情况
leftValue = root->left->val;
}
int rightValue = sumOfLeftLeaves(root->right); // 右
int sum = leftValue + rightValue; // 中
return sum;
}
};
找树左下角的值 513
思路:先找到深度最大再赋值,本题使用前序遍历,最先找到最左边的值。定义一个int变量depth来记录当前遍历的深度,定义一个int变量
result来记录结果
递归三部曲:
1.确定返回值及参数:
给定二叉树求符合条件的节点值,所以传入根节点,传入一个int参数 depthzz来表示当前遍历的深度,返回节点类型int
void travesal(TreeNode* root, int depthzz);
2.确定返回值:
if (root->left == NULL && root->right == NULL) {
if (depth > maxDepth) {
maxDepth = depth; // 更新最大深度
result = root->val; // 最大深度最左面的数值
}
return;
}
3.确定单层递归逻辑:
if(result != nullptr){
depthzz++;
travesal(root->left,depthzz);
depthzz--; //回溯
}
if(result != nullptr){
depthzz ++;
travesal(root->right,depthzz);
depthzz--;//回溯
}
整体C++代码:
class Solution {
public:
int depth = 0;
int result = 0;
void travesal(TreeNode* root, int depthzz){
if(root->left == NULL && root->right == NULL){
if (depth > maxDepth) {
maxDepth = depth; // 更新最大深度
result = root->val; // 最大深度最左面的数值
}
return;
}
if(root->left != nullptr){
depthzz++;
travesal(root->left,depthzz);
depthzz--;
}
if(root->right != nullptr){
depthzz++;
travesal(root->right,depthzz);
depthzz--;
}
}
int findBottomLeftValue(TreeNode* root) {
travesal(root,1);
return result;
}
};
路径总和 112
递归函数什么时候需要返回值,什么时候不需要返回值,特别有的时候返回类型为bool类型,总结如下:
- 需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。
- 需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。
- 不需要搜索整棵二叉树(如找到一条符合的路径)那么递归一定需要返回值,因为遇到符合条件的路径就要及时返回。
思路:
1.确定返回参数及传入参数
本题不需要遍历整棵二叉树,所以递归有返回值,用bool表示。
bool travesal(TreeNode* cur,int count);
2.确定中止条件:
if(cur->left == nullptr && cur->right == nullptr && count == 0) return true;
if(cur->left == nullptr && cur->right == nullptr) return false;
3.确定递归单层逻辑:
if(cur->left != nullptr){
if(travesal(cur->left,count->cur->left->val)) return true;//含回溯逻辑
}
if(cur->right != nullptr){
if(traveal(cur->right,count - cur->right->val)) return true;
}
return false;
整体C++代码:
class Solution {
private:
bool traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right && count == 0) return true; // 遇到叶子节点,并且计数为0
if (!cur->left && !cur->right) return false; // 遇到叶子节点直接返回
if (cur->left) { // 左
count -= cur->left->val; // 递归,处理节点;
if (traversal(cur->left, count)) return true;
count += cur->left->val; // 回溯,撤销处理结果
}
if (cur->right) { // 右
count -= cur->right->val; // 递归,处理节点;
if (traversal(cur->right, count)) return true;
count += cur->right->val; // 回溯,撤销处理结果
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int sum) {
if (root == NULL) return false;
return traversal(root, sum - root->val);
}
};
二叉树的路径综合ii 113
思路:
本题需要搜索整棵二叉树,不用处理递归返回值,所以没有返回参数
1.确定函数返回值及参数
void travesal(TreeNode* root,int target, vector<int> res);
2.确定中止条件
if(root->left == nullptr && root->right == nullptr){
ans.push_back(res);
return;
}
3.确定递归单层逻辑:
if(root->left != nullptr){
res.push_back(root->val);
travesal(root->left,target - root->left->val,res);
res.pop();
}
if(root->right != nullptr){
res,push_back(root->val);
travesal(root->right,target - root->right->val,res);
res.pop_back();
}
整体C++代码:
class Solution {
public:
vector<vector<int>> ans;
void travesal(TreeNode* root,int target,vector<int>& res){
if(root->left == nullptr && root->right == nullptr && target == 0){
ans.push_back(res);
return;
}
if(root->left != nullptr){
res.push_back(root->left->val);
travesal(root->left,target - root->left->val,res);
res.pop_back();
}
if(root->right != nullptr){
res.push_back(root->right->val);
travesal(root->right,target - root->right->val,res);
res.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if(nullptr == root) return ans;
vector<int> res;
res.push_back(root->val);
travesal(root,targetSum-root->val,res);
return ans;
}
};
从中序遍历序列构造二叉树 106
思路:
后序遍历最后一个数一定是二叉树的根节点,再去中序遍历中找到该点,该点往左是以该节点为根节点的左子树,
该点往右是以该节点为根节点的右子树,再以左子树序列去切割后序数组,一层层切割下去,每次后序数组最后一个就是节点元素

*从中序遍历与后序遍历序列构造二叉树 106
思路:
- 1.后序数组大小为0说明是空节点
- 2.如果不为空,去后序数组最后一个元素作为节点元素
- 3.找到后序数组最后一个元素再中序数组的位置,作为切割点
- 4.切割中序数组,切成中序左数组和右数组
- 5.切割后序数组,切成后序左数组和后序右数组(中序数组大小一定是和后序数组的大小相同的)
- 6.递归处理左区间与右区间
C++完整代码:
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, vector<int>& postorder) {
if (postorder.size() == 0) return NULL;
// 后序遍历数组最后一个元素,就是当前的中间节点
int rootValue = postorder[postorder.size() - 1];
TreeNode* root = new TreeNode(rootValue);
// 叶子节点
if (postorder.size() == 1) return root;
// 找到中序遍历的切割点
int delimiterIndex;
for (delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左闭右开区间:[0, delimiterIndex)
vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
// [delimiterIndex + 1, end)
vector<int> rightInorder(inorder.begin() + delimiterIndex + 1, inorder.end() );
// postorder 舍弃末尾元素
postorder.resize(postorder.size() - 1);
// 切割后序数组
// 依然左闭右开,注意这里使用了左中序数组大小作为切割点
// [0, leftInorder.size)
vector<int> leftPostorder(postorder.begin(), postorder.begin() + leftInorder.size());
// [leftInorder.size(), end)
vector<int> rightPostorder(postorder.begin() + leftInorder.size(), postorder.end());
root->left = traversal(leftInorder, leftPostorder);
root->right = traversal(rightInorder, rightPostorder);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
};
用下标索引写出的代码版本:
class Solution {
private:
// 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
if (postorderBegin == postorderEnd) return NULL;
int rootValue = postorder[postorderEnd - 1];
TreeNode* root = new TreeNode(rootValue);
if (postorderEnd - postorderBegin == 1) return root;
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割后序数组
// 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
// 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了
root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
return root;
}
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
// 左闭右开的原则
return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
};
最大二叉树 654
思路:
构造树采用前序遍历,先构造中节点在构造左子树和右子树
1.判断数组大小是否为空,为空时返回空节点
2.获取区间最大值下标
3.构造二叉树节点
4.递归构造左子树及右子树
递归三部曲:
1.确定返回值及输入参数
参数就是存放元素的数组,返回构造二叉树的头节点
2.确定中止条件
if(left == right) return nullptr;//传入的区间为空时直接返回
3.确定单层递归逻辑:
int maxindex = left;
for(int i = left+1;i < right;i++){
if(nums[i] > nums[maxindex]){
maxindex = i;
}
}
TreeNode* root = new TreeNode(nums[maxindex]);
root->left = travesal(nums,left,maxindex);//[0,index)
root->right = travesal(nums,maxindex+1,right);//[index+1,right)
整体C++代码:
TreeNode* travesal(vector<int>& nums,int left, int right){
if(left == right) return nullptr;
int maxindex = left;
for(int i = left+1;i < right;i++){
if(nums[i] > nums[maxindex]){
maxindex = i;
}
}
TreeNode* root = new TreeNode(nums[maxindex]);
root->left = travesal(nums,left,maxindex);//[0,index)
root->right = travesal(nums,maxindex+1,right);//[index+1,right)
return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return travesal(nums,0,nums.size());
}
合并二叉树 617
思路:
本题使用前序遍历,直接再root1上构造新节点,返回root1
考虑出现的所有情况:
1.root1为空,root2为空,无节点需要构造,返回nullptr
2.root1为空,root2不为空,构造值为root2->val的节点,返回该节点
3.root1不为空,root2不为空 无节点需要构造,节点相加
4.root1不为空,root2为空,无节点需要构造,返回nullptr
递归三部曲:
1.确定函数参数及返回值:
输入左右树根节点,返回构造完的新树
TreeNode* travesal(TreeNode* root1, TreeNode* root2);
2.确定中止条件:
if(root1 != nullptr && root2 == nullptr) return nullptr;
if(root1 == nullptr && root2 == nullptr) return nullptr;
3.确定单层递归逻辑:
if(root1 != nullptr && root2 != nullptr) root1->val = root1->val + root2->val;
if(root1 == nullptr && root2 != nullptr) return new TreeNode(root2->val);
TreeNode* cur1 = nullptr;
cur1 = mergeTrees(root1->left,root2->left);
if(cur1 != nullptr){
root1->left = cur1;
}
TreeNode* cur2 = nullptr;
cur2 = mergeTrees(root1->right,root2->right);
if(cur2 != nullptr){
root1->right = cur2;
}
整体C++代码:
TreeNode* travesal(TreeNode* root1, TreeNode* root2){
if(root1 != nullptr && root2 != nullptr) root1->val = root1->val + root2->val;
if(root1 == nullptr && root2 == nullptr) return nullptr;
if(root1 == nullptr && root2 != nullptr) return new TreeNode(root2->val);
if(root1 != nullptr && root2 == nullptr) return nullptr;
TreeNode* cur1 = nullptr;
cur1 = mergeTrees(root1->left,root2->left);
if(cur1 != nullptr){
root1->left = cur1;
}
TreeNode* cur2 = nullptr;
cur2 = mergeTrees(root1->right,root2->right);
if(cur2 != nullptr){
root1->right = cur2;
}
return root1;
}
TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
if(root1 == nullptr) return root2;
if(root2 == nullptr) return root1;
travesal(root1,root2);
return root1;
}
*验证二叉搜索树 98
思路:
不能单纯的比较左节点小于中间节点,右节点大于中间节点
if (root->val > root->left->val && root->val < root->right->val) {
return true;
} else {
return false;
}
我们要比较的是左子树左右节点小于中间节点,右子树所有节点大于中间节点,所以以上代码的逻辑是错误的
例如:

注意题目中最小节点是int的最小值,所以要定义能表示更小数的类型,即long
我们采用中序遍历(二叉搜索树中序遍历是递增序列),递归的同时判断是否递增
递归三步:
1.确定递归函数返回值及输入参数:
判断树是否为二叉搜索树,输入树的根节点,以及上次遍历到节点值(初始化为INT_MIN-1)
bool travesal(TreeNode* root,long& pre_val)
2.确定中止条件:
if(root == nullptr) return true;
3.确定单层递归逻辑
bool leftflag = travesal(root->left,pre_val);
if(false == leftflag){
result = false;
return result;
}
long val = root->val;
if(pre_val < val){
pre_val = val;
}
else return false;
bool rightflag = travesal(root->right,pre_val);
if(false == rightflag){
result = false;
return result;
}
整体C++代码:
class Solution {
public:
bool result = true;
bool travesal(TreeNode* root,long& pre_val){
if(root == nullptr) return true;
bool leftflag = travesal(root->left,pre_val);
if(false == leftflag){
result = false;
return result;
}
long val = root->val;
if(pre_val < val){
pre_val = val;
}
else return false;
bool rightflag = travesal(root->right,pre_val);
if(false == rightflag){
result = false;
return result;
}
return result;
}
bool isValidBST(TreeNode* root) {
long pre_val = -2147483649;
return travesal(root,pre_val);
}
};

浙公网安备 33010602011771号