力扣 5944. 从二叉树一个节点到另一个节点每一步的方向

题目来源:https://leetcode-cn.com/problems/step-by-step-directions-from-a-binary-tree-node-to-another/

大致题意:
给一个二叉树,一个出发节点和一个目的节点,返回出发节点到目的节点的路径,用字符串表示,每一步可以用一个字符表示:

  • ‘L’ 表示从一个节点前往它的 左孩子 节点。
  • ‘R’ 表示从一个节点前往它的 右孩子 节点。
  • ‘U’ 表示从一个节点前往它的 父 节点。

思路

这道题就是寻找最近公共祖先和 dfs 的结合

最近公共祖先 + dfs

首先,需要判断出发节点和目的节点的关系,由此开始找最近公共祖先

  1. 出发节点是目的点的祖先,那么最近公共祖先就是出发节点
  2. 目的点是出发节点的祖先,那么最近公共祖先就是目的点
  3. 除以上两种情况的其他情况,需要寻找最近公共祖先

找到公共祖先后,求出出发点到祖先的路径(U 组成)和祖先到目的点的路径(L, R 组成),这一步可以用 dfs 实现

然后将两段路径拼接就是所求答案

具体看代码:

class Solution {
    StringBuffer sb = new StringBuffer();

    public String getDirections(TreeNode root, int startValue, int destValue) {
        StringBuffer ans = new StringBuffer();
        // 获取最近公共祖先
        TreeNode node = findCommonAncestor(root, startValue, destValue);
        // 若祖先值不为两个值的任意一个
        if (node.val != startValue && node.val != destValue) {
            // 获取开始点到祖先的路径
            dfs(node, startValue);
            // 将路径内容改为 U
            for (int i = 0; i < sb.length(); i++) {
                ans.append('U');
            }
            // 重置
            sb = new StringBuffer();
            // 获取祖先到目的点的路径
            dfs(node, destValue);
            // 因为回溯时添加的路径是由低到高的(也就是目的点到祖先的路径),需要将路径反转一下
            ans.append(sb.reverse());
        } else if (node.val == startValue) {    // 开始节点是目的点的祖先
            dfs(node, destValue);
            ans.append(sb.reverse());
        } else {    // 目的点是开始节点的祖先
            dfs(node, startValue);
            for (int i = 0; i < sb.length(); i++) {
                ans.append('U');
            }
        } 
        return ans.toString();
    }

    public TreeNode findCommonAncestor(TreeNode root, int p, int q) {
        if (root == null) {
            return null;
        }
        // 如果当前节点值为出发点或者目的点,那么开始回溯
        if (root.val == p || root.val == q) {
            return root;
        }
        // 在左子树中递归寻找出发点或者目的点
        TreeNode left = findCommonAncestor(root.left, p, q);
        // 在右子树中递归寻找出发点或者目的点
        TreeNode right = findCommonAncestor(root.right, p, q);
        // 如果左右子树返回值均不为空,表示当前点为公共祖先
        // 该语句只会为 true 一次,也就是找到最近公共祖先那一次
        if (left != null && right != null) {
            return root;
        } else if (left != null) {
            // 左子树返回值不为空,往上回溯
            return left;
        } else {
            // 接下来返回有返回值的右子树递归结果,要么有返回值,要么为空
            return right;
        }
    }

    public TreeNode dfs(TreeNode root, int targetVal) {
        if (root == null) {
            return null;
        }
        // 找到目的点,开始回溯
        if (root.val == targetVal) {
            return root;
        }
        // 在左子树中找目的点
        TreeNode left = dfs(root.left, targetVal);
        // 在右子树中找目的点
        TreeNode right = dfs(root.right, targetVal);
        // 子树不为空,表示找到目的点,回溯并添加路径方向到 StringBuffer 对象(比 str 节约内存)
        if (left != null) {
            sb.append('L');
            return left;
        }
        if (right != null) {
            sb.append('R');
            return right;
        }
        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值