找树左下角的值
给定一个二叉树,在树的最后一行找到最左边的值。
示例 1:
示例 2:
如果用层序遍历就很简单,直接查询最后一个数组的第一位值即可;
由于题目要求得到的是最后一行的最左边的元素,则不能简单的一直向左遍历;两个要求,首先是最后一排,然后再是最左边;
递归判断最后一行最简单的方法就是用最大深度得到最后一行;而且由于这道题的要求是返回左下角的值,所以只需要满足左子树优先遍历即可,那么前序中序后序都可以,保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值;
//确认函数参数和返回值:参数必须有要遍历的树的根节点,还有就是一个int型的变量用来记录最长深度
int maxDepth = INT_MIN; // 全局变量 记录最大深度
int result; // 全局变量 最大深度最左节点的数值
void traversal(TreeNode* root, int depth){//为什么从此处不用int型而是用void型?
//确定函数终止条件
if(root->left == NULL && root->right == NULL){//保证叶节点
if(depth > maxDepth){
maxDepth = depth;//更新深度
result = root->val;//更新深度最左边的数组
}
return;
}
//确定单层递归逻辑 中不需要处理
if(root->left){//左
depth++;
traversal(root->left , depth);
depth--;//回溯
}
if(root->right){//右
traversal(root->right , depth + 1);//隐藏回溯
}
}
整体代码如下:
/**
* 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型的变量用来记录最长深度
int maxDepth = INT_MIN; // 全局变量 记录最大深度
int result; // 全局变量 最大深度最左节点的数值
void traversal(TreeNode* root, int depth){//为什么从此处不用int型而是用void型?
//确定函数终止条件
if(root->left == NULL && root->right == NULL){//保证叶节点
if(depth > maxDepth){
maxDepth = depth;//更新深度
result = root->val;//更新深度最左边的数组
}
return;
}
//确定单层递归逻辑 中不需要处理
if(root->left){//左
depth++;
traversal(root->left , depth);
depth--;//回溯
}
if(root->right){//右
traversal(root->right , depth + 1);//隐藏回溯
}
}
int findBottomLeftValue(TreeNode* root) {
traversal(root,0);
return result;
}
};
路径总和
路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例: 给定如下二叉树,以及目标和 sum = 22,
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
这里讨论一个没有完全懂的点,即递归函数的返回值究竟应该是什么?
如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值;(这种情况就是本文下半部分介绍的113.路径总和ii)
如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值; (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回;(本题的情况)
本题逻辑如图所示:
和上道题一样,无须考虑中的处理逻辑,前中后序都行;
//确定参数类型和返回值
bool traversal(TreeNode* root, int count){
if(root->left == NULL && root->right == NULL){
if(count == 0) return true;//确定终止条件
else return false;
}
if(root->left){//左
count -= root->left->val;
if(traversal(root->left , count)) return true;//注意此时返回值是bool,所以if判断依层返回
count += root->left->val;//回溯 因为要保证对其他路径的count值正常
}
if(root->right){
count -= root->right->val;
if(traversal(root->right, count)) return true;
count += root->right->val;
}
return 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 traversal(TreeNode* root, int count){
if(root->left == NULL && root->right == NULL){
if(count == 0) return true;//确定终止条件
else return false;
}
if(root->left){//左
count -= root->left->val;
if(traversal(root->left , count)) return true;//注意此时返回值是bool,所以if判断依层返回
count += root->left->val;//回溯 因为要保证对其他路径的count值正常
}
if(root->right){
count -= root->right->val;
if(traversal(root->right, count)) return true;
count += root->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(!root) return false;
return traversal(root , targetSum - root->val);
}
};
路径总和Ⅱ
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
示例: 给定如下二叉树,以及目标和 sum = 22,
很简单,层序遍历,返回含有路径数组元素的数组;
由于题目要求遍历所有路径,所以此处迭代函数是没有返回值的;
本体逻辑如图所示:
则整体代码如下:
/**
* 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 {
private:
vector<vector<int>> result;
vector<int> path;
// 递归函数不需要返回值,因为我们要遍历整个树
void traversal(TreeNode* cur, int count) {
if (!cur->left && !cur->right && count == 0) { // 遇到了叶子节点且找到了和为sum的路径
result.push_back(path);
return;
}
if (!cur->left && !cur->right) return ; // 遇到叶子节点而没有找到合适的边,直接返回
if (cur->left) { // 左 (空节点不遍历)
path.push_back(cur->left->val);
count -= cur->left->val;
traversal(cur->left, count); // 递归
count += cur->left->val; // 回溯
path.pop_back(); // 回溯
}
if (cur->right) { // 右 (空节点不遍历)
path.push_back(cur->right->val);
traversal(cur->right, count - cur->right->val);
path.pop_back(); // 回溯
}
return ;
}
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
result.clear();
path.clear();
if (root == NULL) return result;
path.push_back(root->val); // 把根节点放进路径
traversal(root, sum - root->val);
return result;
}
};
从中序和后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树。
注意: 你可以假设树中没有重复的元素。
例如,给出
- 中序遍历 inorder = [9,3,15,20,7]
- 后序遍历 postorder = [9,15,7,20,3] 返回如下的二叉树:
纸上写出来很简单,代码实现很繁琐:
后序数组最后一个元素得到根节点(此处判空处理);
在中序数组中寻找后序数组末尾值分割区间,切割中序数组;
根据中序的左右区间切割后序的左右区间;
递归;
TreeNode* traversal(vector<int>& inorder , vector<int>& postorder){//函数参数和返回值
//终止条件
if(postorder.size() == 0) return NULL:
TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
if(postorder.size() == 1) return root;
//单层递归
int index;
for(index = 0; index < inorder.size(); index++){
if(inorder[index] == root->val) break;
}
//切割数组
//以inorder[index]为分界点切成左右中序
//再以左中序数组得到左后序数组,切割出左右后序数组
//root->left = traversal(左中序,左后序);
//root->right = traversal(左后序,右后序);
//循环不变量:统一左闭右开区间
vector<int> LeftInorder(inorder.begin() , inorder.begin() + index);
vector<int> RightInorder(inorder.begin() + index + 1 , index.end());
postorder.resize(postorder.size() - 1);
vector<int> LeftPostorder(postorder.begin() , postorder.begin() + LeftInorder.size());
vector<int> RightPostorder(postorder.begin() + LeftInorder.size() + 1 , postorder.end());
// 以下为日志
cout << "----------" << endl;
cout << "leftInorder :";
for (int i : leftInorder) {
cout << i << " ";
}
cout << endl;
cout << "rightInorder :";
for (int i : rightInorder) {
cout << i << " ";
}
cout << endl;
cout << "leftPostorder :";
for (int i : leftPostorder) {
cout << i << " ";
}
cout << endl;
cout << "rightPostorder :";
for (int i : rightPostorder) {
cout << i << " ";
}
cout << endl;
root->left = traversal(LeftInorder , LeftPostorder);
root->right = traversal(RightInoder , RightPostorder);
return root;
}
化简vector数组过程,整体代码如下:(提交代码的时候不要打日志,只是要学会使用日志来帮助自己调试)
/**
* 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 inorder_begin , int inorder_end, vector<int>& postorder , int postorder_begin , int postorder_end){//函数参数和返回值
//终止条件
if(postorder_begin == postorder_end) return NULL;
TreeNode* root = new TreeNode(postorder[postorder_end - 1]);
if(postorder_end - 1 == postorder_begin) return root;
//单层递归
int index;
for(index = inorder_begin; index < inorder_end; index++){
if(inorder[index] == root->val) break;
}
//切割数组
//以inorder[index]为分界点切成左右中序
//再以左中序数组得到左后序数组,切割出左右后序数组
//root->left = traversal(左中序,左后序);
//root->right = traversal(左后序,右后序);
//循环不变量:统一左闭右开区间
// vector<int> LeftInorder(inorder.begin() , inorder.begin() + index);
// vector<int> RightInorder(inorder.begin() + index + 1 , index.end());
// postorder.resize(postorder.size() - 1);
// vector<int> LeftPostorder(postorder.begin(), postorder.begin() + LeftInorder.size());
// vector<int> RightPostorder(postorder.begin() + LeftInorder.size() + 1, postorder.end());
int left_inorder_begin = inorder_begin;
int left_inorder_end = index;
int right_inorder_begin = index + 1;
int right_inorder_end = inorder_end;
int left_postorder_begin = postorder_begin;
int left_postorder_end = postorder_begin + left_inorder_end - left_inorder_begin;
int right_postorder_begin = postorder_begin + left_inorder_end - left_inorder_begin;
int right_postorder_end = postorder_end - 1;
//同理,日志如下
cout << "----------" << endl;
cout << "leftInorder :";
for (int i = leftInorderBegin; i < leftInorderEnd; i++) {
cout << inorder[i] << " ";
}
cout << endl;
cout << "rightInorder :";
for (int i = rightInorderBegin; i < rightInorderEnd; i++) {
cout << inorder[i] << " ";
}
cout << endl;
cout << "leftpostorder :";
for (int i = leftPostorderBegin; i < leftPostorderEnd; i++) {
cout << postorder[i] << " ";
}
cout << endl;
cout << "rightpostorder :";
for (int i = rightPostorderBegin; i < rightPostorderEnd; i++) {
cout << postorder[i] << " ";
}
cout << endl;
root->left = traversal(inorder, left_inorder_begin, left_inorder_end, postorder, left_postorder_begin, left_postorder_end );
root->right = traversal(inorder, right_inorder_begin, right_inorder_end, postorder, right_postorder_begin, right_postorder_end);
return root;
}
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());
}
};