513. 找树左下角的值
本题给定一个二叉树,要求找到最底层的最左侧的节点的值。我将在这里阐述两种解题方法:1.递归法 2.迭代法(层序遍历)
1.递归法:
本题使用递归法,是要比迭代法要难的,但是也有很重要知识点在里面,回溯的思想,具体怎么个事,下面看我一步步阐述。
先分析题目,我们需要达成什么样的目标,为了完成这个目标,我们需要考虑那些问题
我们要寻找最底层,最左边的值
那么就会产生以下问题:
1.如何到达最底?
2.如何判断这个节点是整个二叉树的最底层的节点,因为 问题1 只是达到最底的节点,但仅仅只是当前子树的最底层节点,并不是当前整个二叉树的最底层节点。
3.如何到达最左的节点
要达到最底层,我们就要使用递归遍历的方法,然后我就要考虑使用哪个遍历方式(前中后序遍历),那么本题只是找到最左的节点,所以对中间节点的要求不高,我们采用哪种遍历方式都可以,我们姑且先试用前序遍历
那么如何判断这个节点是整个二叉树的最底层的节点呢?我任务需要有一个计数器cnt_node来记录一棵子树到达最底层要经过的节点数,然后再定义一个全局遍历,两个变量相比,就能得出那条路径的节点数是最多的
那么如何到达最左的节点呢?我认为这个可以当做递归的终止条件,当达到最左,并且最底层,就是递归终止之时
要递归遍历,那么就要提到我们的老朋友了,递归三部曲:
1.递归函数的参数及其返回值
函数返回值先定义为void型,因为要有一个int型的变量来记录一条路径的节点数,所以应该有两个参数,第一个当然是TreeNode* node,还有一个就是node_cnt用来记录一条路径上的节点数
2.递归的终止条件
递归的终止条件就是当该结点是最低节点时(该节点访问左右节点都为空)
如果他是最左最低节点时,我们判断它是不是最长路径,如果是,那么改变madep的值,然后让全局变量maxdep等于最长路径的节点数,是全局变量result=该节点的值
if(node->left==NULL&&node->right==NULL){
if(cnt_node>maxdep){
maxdep=cnt_node;
result=node->val;
}
return;
}
3.单层递归的逻辑
单层递归的逻辑,就涉及到回溯问题了
遍历一个节点下去,并且路径节点数加一,该节点遍历完,要返回到上一个节点时,就要将该路径节点数减一;
if (root->left) { // 左
depth++; // 深度加一
traversal(root->left, depth);
depth--; // 回溯,深度减一
}
if (root->right) { // 右
depth++; // 深度加一
traversal(root->right, depth);
depth--; // 回溯,深度减一
}
return;
完整代码如下:
class Solution {
public:
int maxdep=INT_MIN;
int result;
void getnum(TreeNode* node,int cnt_node){
if(node->left==NULL&&node->right==NULL){
if(cnt_node>maxdep){
maxdep=cnt_node;
result=node->val;
}
return;
}
if(node->left){//左
cnt_node++;
getnum(node->left,cnt_node);
cnt_node--;//回溯
}
if(node->right){//右
cnt_node++;
getnum(node->right,cnt_node);
cnt_node--;//回溯
}
return;
}
int findBottomLeftValue(TreeNode* root) {
getnum(root,0);
return result;
}
};
2.迭代法:
是模板题,掌握二叉树的层序遍历即可
具体代码如下:
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*>que;
que.push(root);
int result;
while(!que.empty()){
int size=que.size();
// 这里一定要使用固定大小size,不要使用que.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;
}
};
112. 路径总和
本题想要得到路径之和,那么就要遍历二叉树,要遍历二叉树,我们就可考虑使用递归遍历法,遇到递归,就上递归三部曲:
1.确定递归函数的参数及返回值
由于题目要确定是否存在,所以我们可以把函数返回值设置为bool型,关于参数返回值,我们先写一个TreeNode* node,这时候思考,我们如何判断该条路径上的数是否等于目标值呢,我们就需要引入一个整形来传入目标值,如果我们对路径上的值一个个相加,然后和目标值对比就会比较麻烦,不如直接传入目标值,定义为count,遍历了一个数就将count减去这个目标数,如果个数等于0时并且是到树的底部时,我们结束。
说到这,我们其实已经引出第二条了,确定递归函数的结束条件,就是上面说的:遍历了一个数就将count减去这个目标数,如果个数等于0时并且是到树的底部时,我们结束。当然如果已经到达树底了,但是count仍不为零,也是return
if(node->left==NULL&&node->right==NULL&&count==0) return true;
if(node->left==NULL&&node->right==NULL) return false;
3.确定单层递归的逻辑:
由于这题对中间节点的要求不高,所以我们也无需考虑用哪种遍历方式,直接先后遍历左右节点就行了
当然这里有一个剪枝的操作,如果找到了合适的路径就立即返回:
if (traversal(cur->left, count)) return true;//拿左举例
事实上,本题也包含了回溯的思想,如果这条路径不合适,我们就要将count加回去
所以整体代码如下:
class Solution {
public:
bool getpathadd(TreeNode* node,int count){
if(node->left==NULL&&node->right==NULL&&count==0) return true;
if(node->left==NULL&&node->right==NULL) return false;
if(node->left){
count-=node->left->val;
if(getpathadd(node->left,count)) return true;
count+=node->left->val;
}
if(node->right){
count-=node->right->val;
if(getpathadd(node->right,count)) return true;
count+=node->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root==nullptr) return false;
return getpathadd(root,targetSum-root->val);
}
};