算法力扣刷题记录 四十六【257. 二叉树的所有路径】

前言

二叉树篇【257. 二叉树的所有路径】
回溯体现+1.


一、题目阅读

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径

叶子节点 是指没有子节点的节点。

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

输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]

示例 2:

输入:root = [1]
输出:["1"]

提示:

树中节点的数目在范围 [1, 100] 内
-100 <= Node.val <= 100

二、尝试实现

思路

(1)虽然结果return 类型是vector< string >,但是先用vector< int >搜集到所有路径之后,再整理成string,而且带有“->”符号。
(2)如果搜集每一条路径呢?还是要有遍历顺序。选择后序遍历(错误的),来看下为什么?(包括参考里面直接告诉用前序+递归+回溯,只说中序和后序错了。没说怎么错了。)

  • 用vector<vector>二维数组,放每一条路径,最后整理成string就行(定在主函数中整理)。

  • 对每一条路径,用递归实现。所以下面按步确定函数。

    • 递归的返回值:返回值void。
    • 递归的参数:需要节点TreeNode* cur,需要放路径的数组:vector<vector>& path。
    • 递归终止条件:if(!cur->left && !cur->right) 叶子节点的时候。递归终止逻辑:遇到叶子节点时候,path要新建一个数组,把叶子结点放进去。打算把路径倒着放入数组中,比如“1->2->5”,放到数组中[5,2,1]
  • 后序遍历逻辑:

    1. 先if(!cur->left) traversal(cur->left)。遍历左子树;
    2. 再右子树不为空,添加右子树。
    3. 回到中间节点,把中间节点放到当前path的所有数组中。(bug,有的可以成功,有的不行。如下:)
      在这里插入图片描述
      在这里插入图片描述

(4)所以是中间节点添加位置不对,不应该在左右遍历结束后,对所有数组都加入元素。如果想左边结束,加入一次中间元素;右边遍历结束,加入一次中间元素。那么,不好控制左边遍历结束有几条路径,右边遍历多了几条路径。(卡住……)
(5)所以,后序遍历不行。


三、参考学习

参考思路链接

1.学习内容

  1. 遍历方式:前序遍历(中左右);使用方法:递归+回溯。
  2. 回溯解释——目前接触到的回溯有:
  • 层序遍历递归实现:对当前节点先递归左子树,同时传递深度depth+1;当回归后,depth减回当前深度;再递归右子树,同时传递深度depth+1.记录 三十七的补充最后提到。
  • 记录四十三中最小深度递归法的代码实现 递归左子树时传递深度depth+1。当回归后,再遍历右子树,中间depth相当于先减回当前节点的深度,再+1传递给右子树。
  • 所以,回溯是在递归的“归”出现减少、回退的操作。(浅显先理解)

3.那么找所有路径的时候:遇到叶子节点,说明这是一条路径。再找第二条路径,从叶子节点return,后面的逻辑要退出刚才加入的节点,这就是“减少、回退”,就是回溯
在这里插入图片描述
所以:上图就是整个思路。包含递归:往下传递,并回归;回溯:回归之后,把path中元素减少

代码实现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:
    void traversal(TreeNode* cur,vector<int>& path,vector<string>& result){
        path.push_back(cur->val);
        //终止条件,叶子节点。整理path放到result中
        if(!cur->left && !cur->right){
            string p;
            for(int i = 0;i < path.size();i++){
                p += to_string(path[i]);
                if(i != path.size()-1){
                    p += "->";
                }
            }
            result.push_back(p);
            return;
        }
        //先左后右,前序遍历。
        if(cur->left) {
            traversal(cur->left,path,result);
            //从叶子节点return后,把加入的元素pop
            path.pop_back();
        }
        if(cur->right) {
            traversal(cur->right,path,result);
            path.pop_back();
        }
        return;
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;//定义返回值
        vector<int> path;//路径存放,每一个路径都重复用这个容器,回溯的对象也是它
        traversal(root,path,result);//题目说root至少有一个节点
        return result;
    }
};

重点:

  • 回溯:两个path.pop_back();就是对加入path的节点回归时,pop弹出。回溯和递归是一一对应的,有一个递归,就要有一个回溯

2.精简版本

  1. 参考链接中提到一个精简版本,区别:
  • 记录一条路径的path不用int类型的容器,也不在叶子节点处理时把int转换成string放到result。这两处替换成:
  • 用string类型,边遍历节点,边整理“->”格式。

代码实现2【精简代码】

见注释
可以从【专栏】.记录 三十七的补充记录四十三中最小深度递归法的代码实现中depth传递找到同样的用法。

/**
 * 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:
    void traversal(TreeNode* cur,string path,vector<string>& result){
        //把当前节点的数值加到path上,“->”箭头在有子树的时候才添加传递。
        path += to_string(cur->val);
        //终止条件,叶子节点。把path直接放到result,没有整理的逻辑
        if(!cur->left && !cur->right){
            result.push_back(path);//result用的是引用,所以修改作用到result本身。
            return;
        }
        //左子树
        if(cur->left) traversal(cur->left,path + "->",result);
        //第二个参数path不加引用,所以进入到左子树中path用的是副本,这里的path没变。
        //也就是说,下一层的修改不影响当前这一层。
        if(cur->right) traversal(cur->right,path + "->",result);
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        string path;
        traversal(root,path,result);
        return result;
    }
};

3.迭代法

迭代思路

  • 遍历顺序:前序(中左右)。需要结合前序的迭代实现:有一个栈,用来前序遍历;
  • 记录路径:另外一个栈记录每一条路径,类型是string。如果遇到叶子节点,就把取出的这条路径放到result中。路径的栈变化状态有:
    在这里插入图片描述

代码实现【迭代法】

/**
 * 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<string> binaryTreePaths(TreeNode* root) {
        vector<string> result;
        stack<TreeNode*> st;//放遍历顺序的栈
        stack<string> path;//放路径的栈
        st.push(root);
        path.push(to_string(root->val));
        while(!st.empty()){
            TreeNode* cur = st.top();st.pop();//前序遍历
            string p = path.top();path.pop();//取出节点路径

            if(!cur->left && !cur->right){//是叶子节点
                result.push_back(p);
                continue;
            }
            if(cur->right){//前序遍历先放右节点
                st.push(cur->right);
                //再把这个节点加到路径中
                path.push(p + "->" + to_string(cur->right->val));
            }
            if(cur->left){
                st.push(cur->left);
                //再把这个节点加到路径中
                path.push(p + "->" + to_string(cur->left->val));
            }

        }
        return result;
    }
};

总结

在这里插入图片描述
(欢迎指正,转载标明出处)

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 二叉树的递归遍历: 二叉树的递归遍历是指通过递归方法遍历二叉树的各个节点,按照某种次序访问每个节点。常见的二叉树遍历方式有前序遍历、中序遍历和后序遍历。 2. 二叉树的非递归遍历: 二叉树的非递归遍历是指通过循环等非递归方法遍历二叉树的各个节点,按照某种次序访问每个节点。非递归遍历需要借助栈来实现,常见的二叉树遍历方式有前序遍历、中序遍历和后序遍历。 3. 二叉树的层次遍历: 二叉树的层次遍历是指按照从上到下、从左到右的顺序遍历每一层节点。常用的方法是使用队列来实现,首先将根节点入队列,然后依次出队列,并将其左右子节点入队列,直到队列为空。 4. 输出二叉树上所有叶节点: 二叉树上的叶节点是指没有子节点的节点。可以通过递归方式,对每个节点进行判断,如果该节点没有左右子节点,则将该节点输出。 5. 求二叉树的高度: 二叉树的高度是指从根节点到叶节点最长路径上经过的边数。可以通过递归方式求解,从左右子树中选取较大的一个加上根节点即可。 6. 二叉树层序生成算法二叉树层序生成算法是指按照从上到下、从左到右的顺序依次生成每个节点。可以使用队列来实现,首先将根节点入队列,然后依次出队列,并根据当前节点生成其左右子节点,将其入队列,直到生成完所有节点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值