二叉树中路径问题

11 篇文章 0 订阅

二叉树中和为某一值的路径

题目链接:https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?tpId=13&tqId=11177&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

原文地址:https://mintlucas.github.io/2019/04/20/二叉树中路径问题/

题目来源:剑指Offer

题目描述

输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。

路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

时间限制:1秒 空间限制:32768K 热度指数:167478

解题思路:

**带记忆的 DFS**, 递归

提交记录:

1. 递归结束条件始终有问题;

    注意路径终点是叶节点,而不是子节点

vector<vector<int>> res;

vector<int> buf;

    

    

void dfs(TreeNode *root, int expectNumber){

    

    buf.push_back(root->val);

    

    if(!root->left && !root->right && expectNumber == root->val)

        res.push_back(buf);

        

    //或前加进入判断,空则不进仅走有路的情况,更像图的深搜,终点路径为叶结点

    if(root->left)

        dfs(root->left, expectNumber - root->val);

    if(root->right)

        dfs(root->right, expectNumber - root->val);

        

    buf.pop_back();

}

vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {

    if(root == NULL) return res;

    dfs(root, expectNumber);

    return res;

}

vector<vector<int>> res;

vector<int> buf;



vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {

    if(root == NULL) return;



    expectNumber = expectNumber - root->val;

    

    buf.push_back(root->val);

    

    if (expectNumber == 0 && root->left == NULL && root->right == NULL) {

        res.push_back(buf);

    }

    

    不加if(root->right)但前要加为空返回,多进一层

  

    FindPath(root->left, expectNumber);

    FindPath(root->right, expectNumber);

    

    buf.pop_back();

    

    return res;

}

LeetCode 129. Sum Root to Leaf Numbers

题目链接:(https://leetcode.com/problems/sum-root-to-leaf-numbers/)

解法1:先序遍历的思想(根左右)+数字求和(每一层都比上层和*10+当前根节点的值)

PS:和求二叉树深度等题及其类似,满足叶子结点条件返回某值

int preOrder(TreeNode *root, int sum){

    if(root == NULL)

        return 0;

        

    sum = sum*10 + root->val;

    

    if(root->left == NULL && root->right == NULL)

        return sum;

        

    int sum1 = preOrder(root->left, sum);

    int sum2 = preOrder(root->right, sum);

    

    return sum1 + sum2;

    }

int sumNumbers(TreeNode* root) {

    int sum = preOrder(root, sum);

    return sum;

    }

更详细版:从根结点开始,当每访问到一个结点,我们把该结点添加到路径上,并"累加"

该结点的值,这里"累加"的含义指的是按照题目的要求组成相应的数字即"左移"后相加。

如果该结点为叶结点,那么一条路径搜索完成,将当前所得结果累加。如果当前不是叶子

结点,则继续访问它 的子结点。当前结点访问结束后,递归函数将自动回到它的父结点。

因此我们在函数退出之前要在路径上"删除"当前结点,做法就是将当前路径值/10,以确

保返回父结点时路径刚好是从根结点到父结点的路径。我们不难看出保存路径的数据结构

实际上是一个栈,因为路径要与递归调用状态一致,而递归调用的本质就是一个压栈和出

栈的过程。

class Solution {

public:

    void sumNumbersCore(TreeNode *root, int &pathNum, int &sum) {

        if(root){

            pathNum = pathNum * 10 + root->val;

            //如果是叶子节点,一条路径搜索完成,累加到sum

            if(!root->left && !root->right){

                sum += pathNum;              

            }

            //如果不是叶子节点,则遍历它的子结点

            else{

                if(root->left)

                    sumNumbersCore(root->left, pathNum, sum);

                if(root->right)

                    sumNumbersCore(root->right, pathNum, sum);

            }

            //返回父结点之前,路径上“删除”当前节点

            pathNum /= 10;                    

        }

    }

     

    int sumNumbers(TreeNode *root) {

        int pathNum = 0;

        int sum = 0;

        sumNumbersCore(root, pathNum, sum);

        return sum;

    }

};

解法2:路径问题一般用后续遍历,遍历到当前结点时栈里即为路径结点,再求和即可

int sumOfVector(vector<int> sum){

    int decimal = 1;

    int res = 0;

    for(int i = 0; i < sum.size(); ++i){

        res *= 10;

        res +=  sum[i];

    }

    return res;

}

int sumNumbers(TreeNode *root){

    TreeNode* stk[1000] = {0};

    int top = -1;

    TreeNode *cur = root, *f_last = NULL;

    vector<int> res;

    long long totalSum = 0;

    while(cur || top != -1){

        if(cur){

            stk[++top] = cur;

            cur = cur->left;

        }

        else{

            cur = stk[top];

            if(cur->right && f_last != cur->right){

                cur = cur->right;

            }

            else{

                f_last = cur;

                if(cur->left == NULL && cur->right == NULL){

                    vector<int> sum;

                    for(int i = 0; i <= top; ++i)

                        sum.push_back(stk[i]->val);

                    res.push_back(sumOfVector(sum));

                }

                top--;

                cur = NULL;

            }

        }

    }

    for (int i = 0; i < res.size(); ++i)

        totalSum += res[i];

    return totalSum;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值