记录:LeetCode114

这道题,一开始毫无思路,甚至走错思路,然后经过自己画图,一点一点做出来。一次就 ac,爽到起飞。原来思路对了是这么样的感觉。
这次不像往常,先贴一下结果。在这里插入图片描述


好了,开心完了,进入正题。

题目描述

在这里插入图片描述
看了题目,接下来复现一下心路历程。

心路历程 1

这个单链表,仔细一看顺序,是一个先序遍历。那我要做的就是,按先序遍历的顺序去遍历树,然后,当遍历到右节点时,将右节点接到左节点的尾巴上。(细心的人可能已经发现了,我的思路完全没考虑左右:

但是当时的我没意识到这个问题,一心想的是,如何在递归过程中知道,我已经可以进行链接了。(由于是记录心路历程,所以我把错的思路也往下走,没耐心的朋友直接跳到 2 部分)
那么如何分辨呢,我想到的是,使用一个栈维护遍历结果,当到达叶子节点时,推入一个额外的 null 节点作为标记。只有遇到 null 节点,才进行拼接操作。
在这里插入图片描述

这时候我发现了,我虽然能够按顺序进行链接,但是左右顺序完全乱了。

心路历程2

我一直思考如何从先序遍历入手解决,因为毕竟输出就是先序的。但始终想不出来,无奈我只能完全推翻了思路 1 的思考,从新进行画图。以下是我在思考过程中的图:
在这里插入图片描述

如①,我想的是,要完成变成右链表的话,那么我就得把左子树搬到根与右子树之间。并且,这个操作过程必须得从孩子开始,不能先操作父节点,否则就会乱掉。
然后我就写了一段伪代码(如 ② )。

然后我就开始愉快的敲代码了:

public class Solution1 {
    public void flatten(TreeNode root) {
        if (root == null) return;
        flatten(root.left);
        flatten(root.right);

//        if (root.left == null && root.right == null) return; // 左 null,右 null
//        else if (root.left == null) return; // 左 null,右 not null
//        if (root.right == null && root.left != null) { // 左 not null,右 null
//            root.right = root.left;
//            root.left = null;
//        }
        if (root.left != null){
            TreeNode temp = root.left;
            while (temp.right != null) {
                temp = temp.right;
            }
            temp.right = root.right;
            root.right = root.left;
            root.left = null;
        }
    }
}

我为了方便,先列出了 root 的所有情况:

  1. 为 null
  2. 左空右不空
  3. 左不空右空
  4. 左不空右不空

然后发现,所有的情况都可以归结为一个:
当左节点不为空时,才需要操作。

另外,为了保证先操作子树,我采用的是后序遍历的方式。

事情进行的很顺利,但我马上又发现了问题:
当我要把 1 的左子树插到 1 与右树中间时,我发现按② 的伪代码实现,插入又发生了错误。
节点 5 应该接到节点 4,而不是节点 2。
所以说,在将左子树插入间隔中时,应该寻找左子树的最右子节点。(如③)
于是有了这一段代码:

            TreeNode temp = root.left;
            while (temp.right != null) {
                temp = temp.right;
            }
            temp.right = root.right;
            root.right = root.left;
            root.left = null;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值