LeetCode 第 257 题:“二叉树的所有路径”题解

题解地址:回溯算法(Python 代码、Java 代码)

说明:文本首发在力扣的题解版块,更新也会在第 1 时间在上面的网站中更新,这篇文章只是上面的文章的一个快照,您可以点击上面的链接看到其他网友对本文的评论。

传送门:257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

说明: 叶子节点是指没有子节点的节点。

示例:

输入:

1 /
2 3
5

输出: ["1->2->5", "1->3"]

解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3

回溯算法(Python 代码、Java 代码)

这是典型的使用回溯解决的问题,一般来说,都要使用一个栈或者列表(命名为 path 或者 pre)记录状态,在需要结算的时候,记录下当前的状态。

编码注意事项:回溯的时候状态要重置。

这道题的写法比较多,这里只介绍最基本的回溯、状态重置的写法,其它写法供大家参考。

参考代码 1

Python 代码:

from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        res = []
        if root is None:
            return res
        path = []
        self.__helper(root, path, res)
        return res

    def __helper(self, node, path, res):
        """
        :param node:
        :param path: 沿途经过的结点值组成的列表
        :param res: 存放最终结果的变量
        :return:
        """
        if node is None:
            return
        path.append(str(node.val))
        if node.left is None and node.right is None:
            # 可以结算了
            res.append("->".join(path))
            return
        if node.left:
            self.__helper(node.left, path, res)
            # 【重点】:回溯的时候,要记得弹出
            # 左边结点都看过了,所以 path 要弹出
            path.pop()
        if node.right:
            self.__helper(node.right, path, res)
            # 【重点】:回溯的时候,要记得弹出
            # 右边结点都看过了,所以 path 要弹出
            path.pop()


if __name__ == '__main__':
    node1 = TreeNode(1)
    node2 = TreeNode(2)
    node3 = TreeNode(3)
    node5 = TreeNode(5)

    node1.left = node2
    node1.right = node3
    node2.right = node5

    solution = Solution()
    result = solution.binaryTreePaths(node1)
    print(result)

Java 代码:

import java.util.ArrayList;
import java.util.List;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}


public class Solution {

    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        List<String> path = new ArrayList<>();
        dfs(root, path, res);
        return res;
    }

    private void dfs(TreeNode node, List<String> path, List<String> res) {
        if (node == null) {
            return;
        }
        path.add("" + node.val);
        if (node.left == null && node.right == null) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < path.size(); i++) {
                stringBuilder.append(path.get(i));
                stringBuilder.append("->");
            }
            stringBuilder.delete(stringBuilder.lastIndexOf("->"), stringBuilder.length());
            res.add(stringBuilder.toString());
            return;
        }

        if (node.left != null) {
            dfs(node.left, path, res);
            path.remove(path.size() - 1);
        }
        if (node.right != null) {
            dfs(node.right, path, res);
            path.remove(path.size() - 1);
        }
    }

    public static void main(String[] args) {
        TreeNode node1 = new TreeNode(1);
        TreeNode node2 = new TreeNode(2);
        TreeNode node3 = new TreeNode(3);
        TreeNode node5 = new TreeNode(5);

        node1.left = node2;
        node1.right = node3;
        node2.right = node5;
        Solution solution = new Solution();
        List<String> binaryTreePaths = solution.binaryTreePaths(node1);
        binaryTreePaths.forEach(System.out::println);
    }
}

下面是其它参考代码:

参考代码 2:如果通过参数传递的方式,就没有显式的回溯和状态重置的过程了

说明:下面第 1 个选项卡的 Python 代码是 @何去何从gw 用户在评论区中提供的,并且指出了“隐式回溯”的概念,在此表示感谢。

Python 代码:

from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        res = []
        if root is None:
            return res
        # 注意:根结点的值要先放到 pre 变量中
        self.__helper(root, [str(root.val)], res)
        return res

    def __helper(self, node, pre, res):
        # 隐式回溯
        # pre 表示一组解
        if node is None:
            return
        if node.left is None and node.right is None:
            res.append('->'.join(pre))
        # 通过参数传递的方式,就没有显式的回溯和状态重置的过程了
        if node.left:
            self.__helper(node.left, pre + [str(node.left.val)], res)
        if node.right:
            self.__helper(node.right, pre + [str(node.right.val)], res)

Python 代码:

from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        res = []
        if root is None:
            return res
        self.__helper(root, '', res)
        return res

    def __helper(self, node, pre, res):
        if node.left is None and node.right is None:
            res.append(pre + str(node.val))
            return
        # 通过参数传递的方式,就没有显式的回溯和状态重置的过程了
        if node.left:
            self.__helper(node.left, pre + str(node.val) + '->', res)
        if node.right:
            self.__helper(node.right, pre + str(node.val) + '->', res)

Java 代码:

public class Solution2 {
    
    private void dfs(TreeNode node, String pre, List<String> res) {
        // 递归终止条件:走到根节点的时候,就可以把沿途积累的字符串添加到结果集中
        if (node.left == null && node.right == null) {
            res.add(pre + node.val);
            return;
        }
        if (node.left != null) {
            dfs(node.left, pre + node.val + "->", res);
        }
        if (node.right != null) {
            dfs(node.right, pre + node.val + "->", res);
        }
    }

    public List<String> binaryTreePaths(TreeNode root) {
        // 将全局的结果保存在这里
        List<String> res = new ArrayList<>();
        if (root == null) {
            return res;
        }
        dfs(root, "", res);
        return res;
    }
}

参考代码 3:递归求解

Python 代码:

from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        res = []
        # 前面先讨论递归到底的情况情况
        if root is None:
            return res

        if root.left is None and root.right is None:
            res.append(str(root.val))
            return res

        # 字符串列表
        left_paths = self.binaryTreePaths(root.left)
        for path in left_paths:
            res.append(str(root.val) + '->' + path)
        # 字符串列表
        right_paths = self.binaryTreePaths(root.right)
        for path in right_paths:
            res.append(str(root.val) + '->' + path)

        return res

Python 代码:

from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        res = []

        if root is None:
            return []

        if root.left is None and root.right is None:
            res.append(str(root.val))
            return res

        left_paths = self.binaryTreePaths(root.left)
        for lpath in left_paths:
            res.append(str(root.val) + '->' + lpath)

        right_paths = self.binaryTreePaths(root.right)
        for rpath in right_paths:
            res.append(str(root.val) + '->' + rpath)

        return res

参考代码 4

Python 代码:

from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def binaryTreePaths(self, root: TreeNode) -> List[str]:
        def helper(root, path, res):
            if root is None:
                return True
            path.append(str(root.val))
            left = helper(root.left, path, res)
            right = helper(root.right, path, res)
            if left and right:
                # 如果左边右边都为空,沿途的路径就要结算了
                res.append('->'.join(path))
            # 关键
            path.pop()
            # False 代表空集
            return False

        res = []
        helper(root, [], res)
        return res