513.找树左下角的值
题目链接:513.找树左下角的值
难度指数:😀😐😕
二叉树中最后一行,最靠左侧的值就是我们要求的树左下角的值。
本题迭代法比递归法更简单,迭代法在流程上也比递归法更直观。
本题重点还是建议掌握递归法,因为迭代法比较简单。
我们要求深度最大的叶子节点,它一定是在最后一行;
那么,如何求最后一行最靠左侧的节点?
这就涉及到遍历顺序,这道题使用前中后序遍历都是可以的:中左右、左中右、左右中
本题中是没有中节点的处理逻辑,只要先遍历左就可以,前中后序都是先遍历的左,这样在遍历的过程中,因为优先遍历的是左节点,我们一旦得到了这个深度最大的节点,那么优先遍历的是左节点的话,我们得到的就是最后一行,最靠左侧的节点。
递归解法:
代码思路:
定义一个全局变量,用来记录二叉树里面的最大深度,(因为在递归遍历中,递归到一个深度,就需要把这个最大深度记录下来)
将它初始化为int里面的最小值;
定义一个result,(每次遇到的深度,若比目前这个maxDepth大的话,就更新这个result,这样深度最大的节点的值就放进了result。)
终止条件:
遍历到叶子节点,我们就要去看深度了,我们要找深度最大的叶子节点。
回溯的过程就隐藏在递归函数的下面,(我们平时在写递归的时候,可能没有用到回溯,所以没有注意到)。
int maxDepth = INT_MIN; //记录遍历的所有深度里面最大的深度
int result;
//定义函数的参数和返回值 depth用来记录当前遍历的深度
void traversal(root, depth) {
//终止条件
if (root->left == NULL && root->right == NULL) { //找到叶子节点
if (depth > maxDepth) { //当前叶子节点的深度是不是比maxDepth大
maxDepth = depth; //那么最大深度就需要更新
result = root->val; //同时result要记录当前这个节点的数值
} //(这样result才能是遍历完整个二叉树之后,深度最大的叶子节点最左侧的节点)
}
//确定单层递归的逻辑
//左
if (root->left) { //向左递归遍历,会去确定左孩子是否为空 (避免操作空指针)
depth++;
traversal(root->left, depth);
depth--; //回溯
}
//右
if (root->right) { //若右孩子不为空
depth++;
traversal(root->right, depth);
depth--;
}
}
没有中的处理逻辑
所以本题前、中、后序遍历都可以。
代码写得有点冗余,目的是为了把回溯的过程体现出来。
AC代码: (核心代码模式)
class Solution {
public:
int maxDepth = INT_MIN; //遍历的当前这些深度里面最大的深度
int result;
void traversal(TreeNode* root, int depth) {
if (root->left == NULL && root->right == NULL) { //找到叶子节点
if (depth > maxDepth) {
maxDepth = depth;
result = root->val;
}
}
//左
if (root->left) {
depth++;
traversal(root->left, depth);
depth--; //回溯
}
//右
if (root->right) {
depth++;
traversal(root->right, depth);
depth--;
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return result;
}
};
112.路径总和
题目链接:112.路径总和
难度指数:😀😐
按照题目的意思,
这个二叉树中只要有一条从根节点到叶子节点的路径,相加结果等于 target (即找到一条合法的路径),就返回true;否则返回false。
当看到一个二叉树问题,就要想:如果使用递归法,该采用哪种遍历顺序? 也可以采用迭代法。
本题前、中、后序遍历都可以,因为并不涉及到中的处理逻辑。(即中放在哪里都可以)
递归解法:
代码思路:
确定函数的返回值和参数:返回值是bool类型
只要我们找到一条路径,它的节点之和等于 target(符合条件),那我们就没有必要再遍历其他路径了,直接原地返回就行。
同学会说:参数中
count你应该传入一个0啊,这样我们从根节点往下遍历,遇到一个节点就+1,遇到一个节点就+1,……最后判断
count是否与target相等,再判断是否找到了一条合法的路径。这么想没毛病,但代码实现会麻烦一些。
我们可以:直接向
count传入目标值target,遍历过程中每遇到一个节点,就将count减去这个节点的值,当最后到达叶子节点了,若count= 0,说明沿着该路径的节点数值之和等于target。 (妙啊!)思路差不多,但代码就会简洁一些。
如何找到一条路径,立刻就返回?
靠的是返回值。
确定终止条件:遇到叶子节点了,就要判断这条路径是不是我们想要的。
bool traversal(TreeNode* node, int count) { //需要一个计数器count
//终止条件
if (node->left == NULL && node->right == NULL && count == 0) { //遇到叶子节点,且count = 0时
return true;
}
if (node->left == NULL && node->right == NULL && count != 0) {
return false;
}
//单层递归里面的逻辑
//左
if (node->left) { //若向左不为空,则向左递归
count -= node->left->val;
if (traversal(node->left, count)) return true; //内层:向左递归,外层:如果这个递归返回true,那我们就向上返回true
count += node->left->val; //回溯 (有递归就有回溯)
}
//右
if (node->right) {
count -= node->right->val;
if (traversal(node->right, count)) return true;
count += node->right->val;
}
return false;
}
//左 if (node->left) { //若向左不为空,则向左递归 count -= node->left->val; if (traversal(node->left, count)) return true; //向左递归 count += node->left->val; //回溯 }
向左递归,会有一个返回值返回来
AC代码: (核心代码模式)
class Solution {
public:
bool traversal(TreeNode* node, int count) {
if (node->left == NULL && node->right == NULL && count == 0) {
return true;
}
if (node->left == NULL && node->right == NULL && count != 0) {
return false;
}
//单层递归的逻辑
//左
if(node->left) {
count -= node->left->val;
if (traversal(node->left, count)) return true; //如果递归里面返回的是true,那么我们返回上层的也是true
count += node->left->val; //回溯
}
//右
if (node->right) {
count -= node->right->val;
if (traversal(node->right, count)) return true;
count += node->right->val;
}
return false;
}
public:
bool hasPathSum(TreeNode* root, int sum) {
if (root == NULL) {
return false;
}
return traversal(root, sum - root->val);
}
};
迭代解法:
AC代码: (核心代码模式)
113.路径总和Ⅱ
题目链接:113.路径总和Ⅱ
106.从中序与后序遍历序列构造二叉树
题目链接:106.从中序与后序遍历序列构造二叉树
代码思路:
1️⃣:如果数组大小为零的话,说明是空节点了。
2️⃣:如果不为空,那么取后序数组最后一个元素作为节点元素。
3️⃣:找到后序数组最后一个元素在中序数组的位置,作为切割点
4️⃣:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
5️⃣:切割后序数组,切成后序左数组和后序右数组
6️⃣:递归处理左区间和右区间
//确定递归函数的参数和返回值 (参数是2个数组,中序遍历和后序遍历)
TreeNode* traversal(inorder, postorder) {
if (postorder.size() == 0) {
return null;
}
rootvalue = postorder[postorder.size() - 1]; //2️⃣获取后序数组里面的最后一个元素 (就是根节点元素)
TreeNode* root = new TreeNode(rootvalue);
if (postorder.size() == 1) return root;
index = 0;
for (index = 0; index < index.size(); index++) {
}
}
AC代码: (核心代码模式)
105.从前序与中序遍历序列构造二叉树
题目链接:105.从前序与中序遍历序列构造二叉树