34 二叉树中和为某一值的路径(举例让抽象问题具体化)

题目描述:

输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

(注意: 在返回值的list中,数组长度大的数组靠前)

 

测试用例:

功能测试(二叉树中有一条或者多条符合要求的路径;二叉树中没有符合要求的路径;完全二叉树,只有左子节点或者右子节点

特殊输入测试(空树nullptr)

 

解题思路:

1)规律:当用前序遍历的方式访问到某一个节点时,把该节点添加到路径上,并累加该节点的值。

如果该节点为叶子节点,并且路径中的值的和刚好等于输入的整数,则当前路径符合要求,打印该路径。

如果当前节点不是叶子节点,则继续访问它的子节点。当前节点访问结束后,递归函数将自动回到它的父节点。因此,我们在函数退出之前要在路径上删除当前节点减去当前节点的值,以确保返回父节点时路径刚好是从根节点到父节点。

( 因为int值有正有负,所以不加到最后一个节点(叶子节点)无法判断该路径是否符合。即,要遍历所有路径。)

实现一:牛客通过,但是并没有考虑题目中 “ 在返回值的list中,数组长度大的数组靠前 ”

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        
        if(root==nullptr)return result;
        
        FindPathCore( root, expectNumber);
        return result;

        
    }
    void FindPathCore(TreeNode* root,int expectNumber){
        TreeNode* pNode = root;
        pathNodes.push_back(root->val);
        sum += root->val;
        
        if(sum==expectNumber && pNode->left==nullptr && pNode->right==nullptr){
            //到达根节点
            result.push_back(pathNodes);
        }
        
        //不是叶子节点
        if(pNode->left){//左子树非空
            FindPathCore(pNode->left,expectNumber);
        }
        
        if(pNode->right){//右子树非空
            FindPathCore(pNode->right,expectNumber);
        }
        
        //重要的部分!!!
        //叶子节点。在返回父节点前,在路径上删除当前节点。 
        pathNodes.pop_back();
        sum -= root->val;
    }
private:
    int sum = 0; //用于存储和
    vector<vector<int> > result; //用于存储最终的结果
    vector<int> pathNodes; //用于存储每条路径
};

2)非递归版本

1.按先序遍历把当前节点cur的左孩子依次入栈同时保存当前节点,每次更新当前路径的和sum;
2.判断当前节点是否是叶子节点以及sum是否等于expectNumber,如果是,把当前路径放入结果中。
3.遇到叶子节点cur更新为NULL,此时看栈顶元素,如果栈顶元素的把栈顶元素保存在last变量中,同时弹出栈顶元素,当期路径中栈顶元素弹出,sum减掉栈顶元素,这一步骤不更改cur的值;
4.如果步骤3中的栈顶元素的右孩子存在且右孩子之前没有遍历过,当前节点cur更新为栈顶的右孩子,此时改变cur=NULL的情况。

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root, int expectNumber) {
        stack<TreeNode*> s;
        vector<int> v;
        vector<vector<int> > res;
        while (root || !s.empty()){
            while (root){ //寻找一个路径,压入栈
                s.push(root); v.push_back(root->val); expectNumber -= root->val;
                //能左就左,否则向右
                root = root->left ? root->left : root->right;
            }
            root = s.top(); //指向栈顶,即叶子节点
            if (expectNumber == 0 && root->left == NULL && root->right == NULL)
                res.push_back(v);
            s.pop(); v.pop_back(); expectNumber += root->val;
            //右子数没遍历就遍历,如果遍历就强迫出栈
            if (!s.empty() && s.top()->left == root) 
                root = s.top()->right;
            else
                root = NULL;//强迫出栈
        }
        return res;
    }
};

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 

转载于:https://www.cnblogs.com/GuoXinxin/p/10480024.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值