📌  相关文章
📜  二叉树中任意两个节点之间的打印路径套装2(1)

📅  最后修改于: 2023-12-03 15:36:03.235000             🧑  作者: Mango

二叉树中任意两个节点之间的打印路径套装2

简介

在二叉树中,如果要打印两个任意节点之间的路径,有以下几个问题需要解决:

  • 如何找到两个节点之间的路径
  • 如何打印路径
  • 如何打印所有节点之间的路径

本套装解决了以上三个问题,并提供了多种实现方案。

如何找到两个节点之间的路径

在二叉树中找到两个节点之间的路径可以使用回溯(递归)方法。具体实现如下:

public boolean findPath(TreeNode root, int n, List<Integer> path) {
    if (root == null) {
        return false;
    }
    path.add(root.val);
    if (root.val == n) {
        return true;
    }
    if (findPath(root.left, n, path) || findPath(root.right, n, path)) {
        return true;
    }
    path.remove(path.size() - 1);
    return false;
}

其中,root 为当前节点,n 为目标节点的值,path 为存储路径节点值的列表。函数返回 true 表示找到目标节点,否则返回 false

如何打印路径

找到路径后,我们需要将节点值打印出来。具体实现如下:

public void printPath(List<Integer> path) {
    for (int i = 0; i < path.size(); i++) {
        System.out.print(path.get(i));
        if (i != path.size() - 1) {
            System.out.print("->");
        }
    }
    System.out.println();
}

其中,path 为存储路径节点值的列表。打印完路径后,还需要将 path 清空,以存储下一条路径。

如何打印所有节点之间的路径

打印所有节点之间的路径可以使用回溯(递归)方法。具体实现如下:

public void printAllPaths(TreeNode root, List<Integer> path, List<List<Integer>> paths) {
    if (root == null) {
        return;
    }
    path.add(root.val);
    if (root.left == null && root.right == null) {
        paths.add(new ArrayList<>(path));
    } else {
        printAllPaths(root.left, path, paths);
        printAllPaths(root.right, path, paths);
    }
    path.remove(path.size() - 1);
}

其中,root 为当前节点,path 为存储路径节点值的列表,paths 为存储所有节点之间路径的列表。当 root 为叶子节点时,将 path 加入 paths 提前打印出来。

实现方案

本套装提供了三种实现方案,分别为:

  • 递归实现(Java)
  • 迭代实现(Java)
  • 迭代实现(Python)
递归实现(Java)
public void findAndPrintPath(TreeNode root, int n1, int n2) {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> paths = new ArrayList<>();
    findAndPrintPathHelper(root, n1, n2, path, paths);
}

private void findAndPrintPathHelper(TreeNode root, int n1, int n2, List<Integer> path, List<List<Integer>> paths) {
    if (!findPath(root, n1, path) || !findPath(root, n2, path)) {
        return;
    }
    if (!path.contains(n1) || !path.contains(n2)) {
        return;
    }
    int i = path.indexOf(n1);
    int j = path.indexOf(n2);
    if (i > j) {
        int temp = i;
        i = j;
        j = temp;
    }
    List<Integer> subpath = path.subList(i, j + 1);
    printPath(subpath);
    path.clear();
    paths.clear();
    printAllPaths(root, path, paths);
    for (List<Integer> p : paths) {
        if (p.contains(n1) && p.contains(n2)) {
            printPath(p);
        }
    }
}
迭代实现(Java)
public void findAndPrintPath(TreeNode root, int n1, int n2) {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> paths = new ArrayList<>();
    findAndPrintPathHelper(root, n1, n2, path, paths);
}

private void findAndPrintPathHelper(TreeNode root, int n1, int n2, List<Integer> path, List<List<Integer>> paths) {
    Stack<TreeNode> stack = new Stack<>();
    TreeNode curr = root, prev = null;
    while (curr != null || !stack.isEmpty()) {
        while (curr != null) {
            stack.push(curr);
            path.add(curr.val);
            curr = curr.left;
        }
        curr = stack.peek();
        if (curr.right == null || curr.right == prev) {
            if (curr.val == n1 || curr.val == n2) {
                if (!findPath(root, n1, path) || !findPath(root, n2, path)) {
                    return;
                }
                if (!path.contains(n1) || !path.contains(n2)) {
                    return;
                }
                int i = path.indexOf(n1);
                int j = path.indexOf(n2);
                if (i > j) {
                    int temp = i;
                    i = j;
                    j = temp;
                }
                List<Integer> subpath = path.subList(i, j + 1);
                printPath(subpath);
                path.clear();
                paths.clear();
                printAllPaths(root, path, paths);
                for (List<Integer> p : paths) {
                    if (p.contains(n1) && p.contains(n2)) {
                        printPath(p);
                    }
                }
                return;
            }
            stack.pop();
            path.remove(path.size() - 1);
            prev = curr;
            curr = null;
        } else {
            curr = curr.right;
        }
    }
}
迭代实现(Python)
def find_and_print_path(root, n1, n2):
    stack = []
    curr = root
    prev = None
    path = []
    paths = []
    while curr or stack:
        while curr:
            stack.append(curr)
            path.append(curr.val)
            curr = curr.left
        curr = stack[-1]
        if not curr.right or curr.right == prev:
            if curr.val == n1 or curr.val == n2:
                if not find_path(root, n1, path) or not find_path(root, n2, path):
                    return
                if n1 not in path or n2 not in path:
                    return
                i = path.index(n1)
                j = path.index(n2)
                if i > j:
                    i, j = j, i
                subpath = path[i:j + 1]
                print_path(subpath)
                path.clear()
                paths.clear()
                print_all_paths(root, path, paths)
                for p in paths:
                    if n1 in p and n2 in p:
                        print_path(p)
                return
            stack.pop()
            path.pop()
            prev = curr
            curr = None
        else:
            curr = curr.right
总结

本套装提供了多种实现方案,递归实现代码简洁,但需要额外的存储空间;迭代实现代码稍微复杂,但不需要额外的存储空间,且效率更高。根据实际需求选择实现方案即可。