剑指---树篇(C++)

树篇

第一题:二叉树的前序遍历

题目描述:

在这里插入图片描述
题目思路:
做这题之前要知道二叉树的三种遍历原则:

  • 前序遍历:根-左-右
  • 中序遍历:左-根-右
  • 后序遍历:左-右-根
    如果想深入了解的,可以看我之前写过的这篇文章—>一文搞懂—先序遍历二叉树

解题代码:
方法1: 保存前序遍历的vector数组为全局变量

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    
    
public:
    vector<int> res;   //全局变量直接用于函数内部,不作为形参,它的计算值会实时更新
    vector<int> preorderTraversal(TreeNode* root) {
    
    
        pre_function(root);
        return res; 
    }
    void pre_function(TreeNode* root){
    
    
        if (root == NULL) 
	    {
    
    
		  return; //结束条件
	    }
        res.push_back(root->val);    
        pre_function(root->left);
        pre_function(root->right);
    }
};

方法二: 保存前序遍历的vector数组为局部变量

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    
    
public:
    
    vector<int> preorderTraversal(TreeNode* root) {
    
    
    	vector<int> res;  
        pre_function(root,res);
        return res; 
    }
    void pre_function(TreeNode* root,vector<int> &res){
    
       //这里注意取首地址,而不是vector<int> res
        if (root == NULL) 
	    {
    
    
		  return; //结束条件
	    }
        res.push_back(root->val);    
        pre_function(root->left,res);
        pre_function(root->right,res);
    }
};

补充

//------------------------中序遍历
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    
    
public:
    vector<int> res;   //全局变量直接用于函数内部,不作为形参,它的计算值会实时更新
    vector<int> preorderTraversal(TreeNode* root) {
    
    
        pre_function(root);
        return res; 
    }
    void pre_function(TreeNode* root){
    
    
        if (root == NULL) 
	    {
    
    
		  return; //结束条件
	    }
        pre_function(root->left);
        res.push_back(root->val);  
        pre_function(root->right);
    }
};
//------------------------后序遍历
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    
    
public:
    vector<int> res;   //全局变量直接用于函数内部,不作为形参,它的计算值会实时更新
    vector<int> preorderTraversal(TreeNode* root) {
    
    
        pre_function(root);
        return res; 
    }
    void pre_function(TreeNode* root){
    
    
        if (root == NULL) 
	    {
    
    
		  return; //结束条件
	    }
        pre_function(root->left);
        pre_function(root->right);
        res.push_back(root->val); 
    }
};

第二题: 二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。

数据范围:节点的数量满足 0≤n≤100 ,节点上的值满足 0≤val≤100
进阶:空间复杂度 O(1) ,时间复杂度 O(n)

假如输入的用例为{1,2,3,4,5,#,6,#,#,7},那么如下图:
在这里插入图片描述


题目思路: 传入某节点,调用该方法,返回的应该是以传入节点为根节点的树的深度,而树的深度,肯定和左右子树深度有关,所以进入这个方法后,就包含了左右子树的深度(而要得到左右子树的深度,肯定又是以左右子节点为根节点,再次调用该方法深度获取的,因此此时进行递归),并且还有由一个左右深度比较的过程,然后取较大值,这个较大值就是该节点左右子树深度较深的值,以该值+1作为返回值,就是该节点的深度。

看下图:
在这里插入图片描述


代码部分:

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
    
    
public:
    int TreeDepth(TreeNode* pRoot) {
    
    
    if (pRoot==NULL){
    
    
        return 0;
    }
        else{
    
    
        //声明a、b两个变量分别记录得到的左右子树深度。
            int a=TreeDepth(pRoot->left);
            int b=TreeDepth(pRoot->right);
            //进行比较,较大值+1作为返回值
            return a>b?(a+1):(b+1);
        }
    }
};

第三题: 二叉树的镜像

描述
操作给定的二叉树,将其变换为源二叉树的镜像。
数据范围:二叉树的节点数0≤n≤1000 , 二叉树每个节点的值0≤val≤1000
要求: 空间复杂度 O(n) 。本题也有原地操作,即空间复杂度 O(1) 的解法,时间复杂度 O(n).
在这里插入图片描述


题目思路: 如下图所示,我们需要做的是,从上自下依次更换每一层的左右子树的顺序。至此,可以采用递归的方法。在这里插入图片描述


代码部分:

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    
    
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pRoot TreeNode类 
     * @return TreeNode类
     */
    TreeNode* Mirror(TreeNode* pRoot) {
    
    
        if(pRoot==NULL){
    
    
            return pRoot;
        }
        //交换左右子树的信息
        TreeNode* temp=pRoot->left;
        pRoot->left=pRoot->right;
        pRoot->right=temp;
        //然后继续对左右子树的子树进行交换,在此直接递归即可
        Mirror(pRoot->left);
        Mirror(pRoot->right);
        //最后返回根节点的信息
        return pRoot;
    }
};

第四题: 从上往下打印二叉树

描述
不分行从上往下打印出二叉树的每个节点,同层节点从左至右打印。例如输入{8,6,10,#,#,2,1},如以下图中的示例二叉树,则依次打印8,6,10,2,1(空节点不打印,跳过),请你将打印的结果存放到一个数组里面,返回。
数据范围:
0<=节点总数<=1000
-1000<=节点值<=1000
在这里插入图片描述
题目思路:
题目给出一颗二叉树,我们需要按照从上到下,从左到右的顺序遍历节点。也就是从上到下一层一层的遍历。
对于BFS(广度优先算法),我们可以利用一个队列来存储我们需要访问的节点。当我们访问一个节点的时候,将这个节点的值放入要输出的数组里面,然后这节点出队。然后我们先判断左边的节点是否为空,若不为空,那么将这个节点指针入队,对右边的节点的判断也是一样。一直执行下去直到最后队列为空。另外记得特判根节点为空的情况
补充!
广度优先搜索算法(Breadth-First-Search,缩写为 BFS),是一种利用队列实现的搜索算法。简单来说,其搜索过程和 “湖面丢进一块石头激起层层涟漪” 类似。

深度优先搜索算法(Depth-First-Search,缩写为 DFS),是一种利用递归实现的搜索算法。简单来说,其搜索过程和 “不撞南墙不回头” 类似。

BFS 的重点在于队列,而 DFS 的重点在于递归。这是它们的本质区别。


代码部分:
也可以结合画图进一步理解整个搜索过程

class Solution {
    
    
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
    
    
        vector<int> ret;  //存放结果的数组
        if (!root) return ret;
        queue<TreeNode*> q;  //定义一个队列
        q.push(root);        //将根节点传入队列
        while (!q.empty()) {
    
    
            TreeNode *node = q.front();  //将根节点的值赋给*node
            ret.push_back(node->val);
            q.pop();  //弹出根节点
            
            if (node->left) q.push(node->left);  //如果左子树不为空,将左子树入队
            if (node->right) q.push(node->right);//如果右子树不为空,将右子树入队
        }
        return ret;
    }
};

第五题:求二叉树的层序遍历

依旧是求层序遍历的问题,但是这次要求输出的形式为二维数组
具体描述如下:在这里插入图片描述
解题思路:
在这里插入图片描述
首先拿出根节点,如果左子树/右子树不为空,就将他们放入队列中。
第一遍处理完后,根节点已经从队列中拿走了,而根节点的两个孩子已放入队列中了,现在队列中就有两个节点 25
在这里插入图片描述
第二次处理,会将 25 这两个节点从队列中拿走,然后再将 25 的子节点放入队列中,现在队列中就有三个节点 346
在这里插入图片描述
我们把每层遍历到的节点都放入到一个结果集中,最后返回这个结果集就可以了。

代码部分:

/**
 * 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>> levelOrder(TreeNode* root) {
    
    
        vector<vector<int>> res;  //返回结果(二维数组)
        if(root == nullptr){
    
    
            return res;
        }
        queue<TreeNode*> ret;    //定义一个队列,用于层次遍历节点
        ret.push(root);          //将树的根节点传入队列
        while(!ret.empty()){
    
    
            int Size = ret.size();    //接受当前层的大小,便于传入下一层的子树
            vector<int> Array;        //用于保存每一层队列中的元素
            for(int i = 0; i < Size; i++){
    
    
                TreeNode* node = ret.front();   //将根结点赋给node
                Array.push_back(node->val);             //将根节点中的值传递到数组中
                ret.pop();                      //将队列中的元素出队
                if(node->left){
    
                     //如果出队的元素有左右节点,那么传进来
                    ret.push(node->left);
                }
                if(node->right){
    
    
                    ret.push(node->right);
                }
            }
            res.push_back(Array);
        } 
        return res;
    }
};

第六题: 对称的二叉树

描述
给定一棵二叉树,判断其是否是自身的镜像(即:是否对称)
例如: 下面这棵二叉树是对称的

在这里插入图片描述
题目思路:
当且仅当两棵子树符合如下要求时,满足 “对称” 要求:

  • 两棵子树根节点值相同;

两颗子树的左右子树分别对称,包括:

  • a 树的左子树与 b 树的右子树相应位置的值相等
  • a 树的右子树与 b 树的左子树相应位置的值相等

具体的,我们可以设计一个递归函数 check ,传入待检测的两颗子树的头结点 a 和 b(对于本题都传入 root 即可),在单次查询中有如下显而易见的判断子树是否 “对称” 的 Base Case:

  • a 和 b 均为空节点:符合 “对称” 要求;
  • a 和 b 其中一个节点为空,不符合 “对称” 要求;
  • a 和 b 值不相等,不符合 “对称” 要求;

其他情况,我们则要分别检查 a 和 b 的左右节点是否 “对称” ,即递归调用 check(a.left, b.right) 和 check(a.right, b.left)。


代码部分:

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};
*/
class Solution {
    
    
public:
    bool isSymmetrical(TreeNode* pRoot) {
    
    
    return check(pRoot,pRoot);//进入check函数从根节点进行检测
    }
    bool check(TreeNode* a,TreeNode* b){
    
      //一左一右
        if((a==NULL)&&(b==NULL))return true;   //如果两者都为空,那么是镜像的
        if((a==NULL)||(b==NULL))return false;  //一个为空一个不为空,非镜像
        if((a->val)!=(b->val))return false;  //两者值不相等,非镜像
        return check(a->left,b->right)&&check(a->right,b->left);  //继续递归检查左右子树
    }
};

第七题: 二叉树中和为某一值的路径(一)

描述
给定一个二叉树root和一个值 sum ,判断是否有从根节点到叶子节点的节点值之和等于 sum 的路径。
1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点
2.叶子节点是指没有子节点的节点
3.路径只能从父节点到子节点,不能从子节点到父节点
4.总节点数目为n在这里插入图片描述
题目思路:

定义递归函数功能: 判断是否当前结点到root为止的路径和为sum

  • 每次递归都减掉经过的结点的值
  • 当前结点是叶子结点,并且sum刚好为0,表明该路径和刚好为sum
  • 返回时,保证能递归每个结点,且只需要有一条路径满足即可

图示:在这里插入图片描述


代码部分:

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 * };
 */

class Solution {
    
    
public:
    /**
     * 
     * @param root TreeNode类 
     * @param sum int整型 
     * @return bool布尔型
     */
    bool hasPathSum(TreeNode* root, int sum) {
    
    
      if (root == NULL)
            return false;
        // 每次递归都减掉经过的结点的值
        sum -= root->val;
        // 当前结点是叶子结点,并且sum刚好为0,表明该路径和刚好为sum
        if (sum == 0 && root->left == NULL && root->right == NULL)
            return true;
        // 保证能递归每个结点,且只需要有一条路径满足即可
        // 本质上是DFS深度优先遍历,只是由递归实现
        return hasPathSum(root->left, sum) || hasPathSum(root->right, sum);
    }
};

第八题: 判断是不是平衡二叉树

描述
输入一棵节点数为 n 的二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1 (即等于1也可以),并且左右两个子树都是一棵平衡二叉树。
样例解释:在这里插入图片描述
题目思路:
解法一:自顶向下(前序遍历)
一棵二叉树为「平衡二叉树」的条件为:该树为空树,或者其左右子树的高度差最大为1。因此,判断一棵二叉树是否平衡需要求其子树高度,并比较左右子树高度差。

因此此题的解题步骤如下:

  • 设计「求二叉树高度」的函数getHeight(root),作用是求以root为根结点的二叉树高度;
  • 遍历原二叉树,对其每个结点调用getHeight(root)函数,若存在某左右子树的高度差大于等于2,则是不平衡的;否则是平衡二叉树。
    求取二叉树高度的思路如图所示。在这里插入图片描述

图中,红色箭头方向为递归方向,绿色箭头方向为回溯方向。

  • 当结点为空时,其高度为0;
  • 当结点无左孩子、右孩子时,其高度为1;
  • 否则,该结点的高度为max(左子树高度,右子树高度) + 1。(加1是因为要加上该结点本身)

代码部分:

class Solution {
    
    
public:
    bool IsBalanced_Solution(TreeNode* root) {
    
    
        if (!root)  //为空,则是平衡二叉树
            return true;
        // 分别求左子树和右子树高度
        int leftHeight = getHeight(root->left), rightHeight = getHeight(root->right);
        // 若子树高度之差大于1,返回false
        if (abs(leftHeight - rightHeight) > 1) 
            return false;
        // 递归地判断左右子树是否平衡
        return IsBalanced_Solution(root->left) && IsBalanced_Solution(root->right);
    }
    // 求子树高度的函数
    int getHeight(TreeNode* root) {
    
    
        if (!root) 
            return 0;
        if (!root->left && !root->right) 
            return 1; // 叶子结点
        return 1 + max(getHeight(root->left), getHeight(root->right));
    }
};



解法二:自底向上(后序遍历)
解法一在「计算二叉树高度」时遍历了树的结点,在「判断是否平衡」时又遍历了一次树的结点,因此产生了重复计算。
说具体点就是:从1开始判断,用getHeight函数求深度时,要遍历2、4、5,而在判断以2为根的树是否为平衡二叉树时也要遍历4、5。因此,这种方法存在着许多重复的计算。
针对解法一的优化是采用「自底向上」的解题思路:

  • 从最底的叶子结点开始,计算该结点的高度。若该结点不平衡,则直接返回-1,不用继续计算其他结点高度,否则返回其高度;
  • 若自底向上的过程中一直都是平衡的,则最终的树是平衡的。此方法每个结点(最坏时)仅会遍历一次,不会有重复计算。在这里插入图片描述

代码部分:

class Solution {
    
    
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
    
    
        if (!pRoot) 
            return true; 
        return getHeight(pRoot) >= 0; // 若结果不是-1,则是平衡的
    }
    int getHeight(TreeNode* root) {
    
    
        if (!root) 
            return 0;   //递归到叶子节点时子树为空,用于回溯
        // 左子树高度
        int left = getHeight(root->left); 
        if (left == -1) 
            return -1; // 若左子树高度为-1,则不平衡
        int right = getHeight(root->right); // 右子树高度
        if (right == -1 || abs(left - right) >= 2) 
            return -1; // 若右子树高度为-1,或左右子树高度之差大于1,则不平衡
        return 1 + max(left, right); // 返回该结点高度
    }
};

第九题:相同的树

题目描述:
在这里插入图片描述

题目思路:
解法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:
    bool isSameTree(TreeNode* p, TreeNode* q) {
    
    
        if(p==nullptr&&q==nullptr){
    
         //两个都为空
            return true;
        }else if(p==nullptr||q==nullptr){
    
      //一个为空,一个不为空
            return false;
        }else if(p->val!=q->val){
    
       //都不为空,但是值不相等
            return false;
        }
        return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);  //继续递归
    }
};

解法2:广度优先搜索

  • 利用队列进行层次遍历
  • 先后遍历两个树,将val的值传入数组,通过比较两个数组中的元素是否相同,来验证这两个树是否相同
  • 由于定义的是Int型的数组,对于空子树,可以传入0

解题代码:

class Solution {
    
    
public:
    bool isSameTree(TreeNode* root1, TreeNode* root2) {
    
    
        if(root1 == nullptr&&root2 == nullptr){
    
    
            return true;     //两个都为空,说明相同
        }
        if(root1 == nullptr||root2 == nullptr){
    
    
            return false;    //一个为空,一个不为空,说明不同
        }
        queue<TreeNode*> que;
        que.push(root1);
        vector<int> arr1,arr2;
        while(!que.empty()){
    
    
            int Size = que.size();
            for(int i = 0;i < Size;i++){
    
    
                TreeNode* node = que.front();
                arr1.push_back(node->val);
                que.pop();
                if(node->left){
    
    
                    que.push(node->left);
                }else{
    
    
                    arr1.push_back(0);
                }
                if(node->right){
    
    
                    que.push(node->right);
                }else{
    
    
                    arr1.push_back(0);
                }
            }
        }
        que.push(root2);
        while(!que.empty()){
    
    
            int Size = que.size();
            for(int i = 0;i < Size;i++){
    
    
                TreeNode* node = que.front();
                arr2.push_back(node->val);
                que.pop();
                if(node->left){
    
    
                    que.push(node->left);
                }else{
    
    
                    arr2.push_back(0);
                }
                if(node->right){
    
    
                    que.push(node->right);
                }else{
    
    
                    arr2.push_back(0);
                }
            }
        }
        return arr1==arr2;
    }
};

第十题:合并二叉树

题目描述:
在这里插入图片描述
题目思路:
dfs:深度优先搜索
终止条件:树 1 的节点为 null,或者树 2 的节点为 null
递归函数内:将两个树的节点相加后,再赋给树 1 的节点。再递归的执行两个树的左节点,递归执行两个树的右节点
解题代码:

//简洁的解法一,个人更喜欢解法二
class Solution {
    
    
public:
    /**
     * 
     * @param t1 TreeNode类 
     * @param t2 TreeNode类 
     * @return TreeNode类
     */
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
    
    
        // write code here
        if(!t1) return t2;
        if(!t2) return t1;   //如果t2节点不存在,则用t1
        t1->val = t1->val + t2->val;  //t1 t2都存在,t1的值更新为两节点值之和
        t1->left = mergeTrees(t1->left, t2->left);
        t1->right = mergeTrees(t1->right, t2->right);
        return t1;
    }
};
/*   解法二
终止条件:树 1 的节点为 null,或者树 2 的节点为 null
递归函数内:将两个树的节点相加后,再赋给树 1 的节点。再递归的执行两个树的左节点,递归执行两个树的右节点
*/
class Solution {
    
    
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
    
    
        if(root1 == nullptr || root2 == nullptr){
    
         //很高级的写法,避免了使用两个if
            return root1 == nullptr ? root2 : root1;
        }
        return dfs(root1,root2);    //调用深度优先搜索
    }
    TreeNode* dfs(TreeNode* r1, TreeNode* r2){
    
       //这里无论是再root1还是root2上修改都行,本程序默认root1
        if(r1 == nullptr || r2 == nullptr){
    
    
            return r1 == nullptr ? r2 : r1;     //注意这里返回的是指针,不是数值
        }
        r1 -> val = r1 -> val + r2 -> val;     //说明r1和r2的当前指向都不为空,那么将两者的值相加
        r1 -> right = dfs(r1 -> right,r2 -> right);  
        r1 -> left = dfs(r1 -> left,r2 -> left);
        return r1;
    }
};

第十一题:左叶子之和

题目描述:
在这里插入图片描述

题目思路:
广度优先搜索—BFS

  • 定义一个sum,用于存放左子树之和 int sum = 0;
  • 可以观察每一层,以上图为例,在第二层中,我们可以判断2和3的左子树是否存在,如果存在并且其左右子树为空,那么就sum+=。
  • 注意,右子树可以不考虑对其进行sum,但是需要加进去进行迭代

解题代码:

/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
    
    
public:
    int sum = 0;
    int sumOfLeftLeaves(TreeNode* root) {
    
    
        if(root == nullptr){
    
    
            return 0;
        }
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()){
    
    
            int Size = que.size();
            for(int i = 0;i < Size;i++){
    
    
                TreeNode* node = que.front();
                que.pop();
                if(node->left){
    
    
                    que.push(node->left);
                }
                if(node->right){
    
    
                    que.push(node->right);
                }
                if((node->left!=nullptr)&&node->left->left==nullptr&&node->left->right==nullptr){
    
       
                //前半句保证了我们累加的是左子树;后半句保证了左子树是叶子节点
                    sum+=node->left->val;
                }
            }
        }
        return sum;
    }
};

深度优先搜索—DFS

解题代码:

class Solution {
    
    
public:
    int sumOfLeftLeaves(TreeNode* root) {
    
    
        if(root == nullptr){
    
    
            return 0;
        }
        int sum = 0;
        if((root->left!=nullptr) && root->left->left == nullptr && root->left->right == nullptr){
    
    
            sum += root->left->val;
            sum += sumOfLeftLeaves(root->right);
            return sum;
        }
        sum += sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);   //这里类似于层次遍历中的判断下一层的左右子树
        return sum;
    }
};

第十二题:路径总和

题目描述:
在这里插入图片描述

题目思路:
一定要注意审题,题目中说的是根节点到叶子节点的路径和。
解法1:BFS

  • 首先我们可以想到使用广度优先搜索的方式,记录从根节点到当前节点的路径和,以防止重复计算。

  • 这样我们使用两个队列,分别存储将要遍历的节点,以及根节点到这些节点的路径和即可。

解题代码:

class Solution {
    
    
public:
    bool hasPathSum(TreeNode *root, int sum) {
    
    
        if (root == nullptr) {
    
    
            return false;
        }
        queue<TreeNode *> que_node;   //队列一,操作树
        queue<int> que_val;           //队列二,比较目标和
        que_node.push(root);
        que_val.push(root->val);
        while (!que_node.empty()) {
    
    
            TreeNode *now = que_node.front();     //和下面一行代码成对出现
            int temp = que_val.front();
            que_node.pop();                       //和下面一行代码成对出现
            que_val.pop();
            if (now->left == nullptr && now->right == nullptr) {
    
        //注意审题!!! 题目中要求的是从根节点到叶子节点的路径
                if (temp == sum) {
    
    
                    return true;       //说明根节点就是目标和
                }
                continue;
            }
            if (now->left != nullptr) {
    
    
                que_node.push(now->left);
                que_val.push(now->left->val + temp);
            }
            if (now->right != nullptr) {
    
    
                que_node.push(now->right);
                que_val.push(now->right->val + temp);
            }
        }
        return false;
    }
};

解法2:DFS
假定从根节点到当前节点的值之和为 val,我们可以将这个大问题转化为一个小问题:是否存在从当前节点的子节点到叶子的路径,满足其路径和为 sum - val

不难发现这满足递归的性质,若当前节点就是叶子节点,那么我们直接判断 sum 是否等于 val 即可(因为路径和已经确定,就是当前节点的值,我们只需要判断该路径和是否满足条件)。若当前节点不是叶子节点,我们只需要递归地询问它的子节点是否能满足条件即可。

class Solution {
    
    
public:
    bool hasPathSum(TreeNode *root, int sum) {
    
    
        if (root == nullptr) {
    
    
            return false;
        }
        if (root->left == nullptr && root->right == nullptr) {
    
       
        //这两行代码只有碰到叶子节点才会执行
        //由于先前的sum作为输入参数,每次都减root->val
        //因此如果最后叶子节点的值=减完之后sum的值,说明这条路是对的。
            return sum == root->val;   
        }
        return hasPathSum(root->left, sum - root->val) ||
               hasPathSum(root->right, sum - root->val);
    }
};

注: 以上题目都是在牛客网的剑指offer题库中刷的,有自己做的,也有不会做看别人精华解题思路,然后总结的。如果侵犯了您的权益,请私聊我。
最后,觉得本文内容对你有所帮助的话,感谢点赞收藏!

算法篇的题库还在持续更新中,小伙伴们不要着急。
导航链接:必刷算法题—二分查找(C++)
导航链接:必刷算法题—排序篇(C++)
导航链接:必刷算法题—哈希篇(C++)
导航链接:剑指—动态规划篇(C++)
导航链接:剑指—链表篇(C++)
导航链接:剑指—队列&栈篇(C++)

猜你喜欢

转载自blog.csdn.net/qq_40077565/article/details/121324567