题目:
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
想法:
递归+回溯的方法,遵循递归函数的思考规则。记录深度,深度要回溯。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth = INT_MIN;
int result;
//递归函数 输入参数:节点指针 当前层深度 无返回值
void traversal(TreeNode* node, int depth) {
//终止条件 遍历到了叶子节点 判断是否是最大深度,如果是最大深度要更新结果值,一定要大于才更新,等于不用更新
//因为采用先左后右的方式深度遍历,这样在遇到新的一层最左边的叶子节点时才会更新结果,保证是最左边节点的值
if (!node -> left && !node -> right) {
if (depth > maxDepth) {
maxDepth = depth;
result = node -> val;
return ;
}
}
if (node -> left) {
//隐藏回溯
traversal(node -> left, depth + 1);
}
if (node -> right) {
//隐藏回溯
traversal(node -> right, depth + 1);
}
return ;
}
int findBottomLeftValue(TreeNode* root) {
//迭代法层序遍历更简单,这里复习递归法和回溯
traversal(root, 1);
return result;
}
};
题目:
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
想法:
技巧:用目标值减当前节点值向下递归。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//递归+回溯 直接利用原函数作为递归函数 定义递归函数的意义为:返回当前节点是否为满足目标和的路径
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
//终止条件 遇到叶子节点 判断路径值和是否等于目标和
if (!root -> left && !root -> right && targetSum == root -> val) return true;
if (!root -> left && !root -> right) return false;
if (root -> left) {
if (hasPathSum(root -> left, targetSum - root -> val)) return true;
}
if (root -> right) {
if (hasPathSum(root -> right, targetSum - root -> val)) return true;
}
return false;
}
};
题目:
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
想法:
这个是自己写的,有了上一道题的经验,加入path记录路径,注意回溯就行了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//存结果
vector<vector<int>> result;
//递归函数 递归+回溯 path记录路径节点值 引用需要回溯
void traversal(TreeNode* node, int targetSum, vector<int>& path) {
if (node == nullptr) return ;
path.push_back(node -> val);
//终止条件
if (!node -> left && !node -> right && targetSum == node -> val) {
result.push_back(path);
}
if (node -> left) {
traversal(node -> left, targetSum - node -> val, path);
//回溯
path.pop_back();
}
if (node -> right) {
traversal(node -> right, targetSum - node -> val, path);
//回溯
path.pop_back();
}
return ;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
traversal(root, targetSum, path);
return result;
}
};
题目:
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
想法:
二叉树序列化,之前学习过,这次加深印象。==注意理清逻辑,脑子里要一直想着两个表会好写一些。==统一不变量,即左闭右开区间。可以用下标简化表示,这里我就直接用下标去写的,中间犯了一个错误,终止条件少考虑了一种。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//用索引表示分割出的区间 统一规定采用左闭右开
//递归函数 返回以下标表示的区间内的中序 后序遍历形成的二叉树根节点
TreeNode* traversal(vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
//这里犯了错误 少写这个导致bug
if (postorderBegin == postorderEnd) return nullptr;
//终止条件 只剩一个值
if (inorderEnd - 1 == inorderBegin) {
TreeNode* node = new TreeNode(inorder[inorderBegin]);
return node;
}
//通过后序遍历确认当前构成树的根节点的值
int val = postorder[postorderEnd - 1];
TreeNode* node = new TreeNode(val);
//递归遍历填上左右子树的节点地址
//确认中序遍历的分隔区间
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == val) break;
}
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
//确认后序遍历的分隔区间
int leftPostorderBegin = postorderBegin;
int leftPostorderEnd = postorderBegin + (delimiterIndex - inorderBegin);
int rightPostorderBegin = leftPostorderEnd;
int rightPostorderEnd = postorderEnd - 1;
node -> left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
node -> right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
return node;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return nullptr;
int size = inorder.size();
return traversal(inorder, 0, size, postorder, 0, size);
}
};
题目:
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
想法:
一样的思路,稍稍改一下就出来了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//用索引表示分割出的区间 统一规定采用左闭右开
//递归函数 返回以下标表示的区间内的中序 后序遍历形成的二叉树根节点
TreeNode* traversal(vector<int>& preorder, int preorderBegin, int preorderEnd, vector<int>& inorder, int inorderBegin, int inorderEnd) {
if (preorderBegin == preorderEnd) return nullptr;
//终止条件 只剩一个值
if (inorderEnd - 1 == inorderBegin) {
TreeNode* node = new TreeNode(inorder[inorderBegin]);
return node;
}
//通过前序遍历确认当前构成树的根节点的值
int val = preorder[preorderBegin];
TreeNode* node = new TreeNode(val);
//递归遍历填上左右子树的节点地址
//确认中序遍历的分隔区间
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == val) break;
}
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
//确认后序遍历的分隔区间
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = leftPreorderBegin + (delimiterIndex - inorderBegin);
int rightPreorderBegin = leftPreorderEnd;
int rightPreorderEnd = preorderEnd;
node -> left = traversal(preorder, leftPreorderBegin, leftPreorderEnd, inorder, leftInorderBegin, leftInorderEnd);
node -> right = traversal(preorder, rightPreorderBegin, rightPreorderEnd, inorder, rightInorderBegin, rightInorderEnd);
return node;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0 || inorder.size() == 0) return nullptr;
int size = preorder.size();
return traversal(preorder, 0, size, inorder, 0, size);
}
};