0
点赞
收藏
分享

微信扫一扫

展开二叉搜索树之中序遍历+dummyNode || 回溯核心

回溯核心

前言

一、案例

给你一棵二叉搜索树,请 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没有左子节点,只有一个右子节点。
在这里插入图片描述

二、题解

package com.xhu.offer.offerII;

//展开二叉搜索树
public class IncreasingBST {
    //回溯改变树结构,自底向上把每一棵子树当作一棵完整二叉排序树,拿到首节点和尾节点来改变树结构。首尾节点即最左最右节点,最后返回最左节点即可。
    public TreeNode increasingBST(TreeNode root) {
        //回溯改变树结构,通过首尾即最左最右节点来改变树结构
        TreeNode[] res = order(root);
        //返回最左节点,即首节点,也即新树的根节点。
        return res[0];
    }

    private TreeNode[] order(TreeNode root) {
        //情况1:左右孩子单边为空的情况,此时最左或最右节点应变为root节点,以返回null示意。
        if (root == null) return null;
        //情况2:叶子节点,特殊节点,返回特殊化,左右都返回root,统一改变树结构的操作。
        if (root.left == null && root.right == null) return new TreeNode[]{root, root};
        //拿到左右子树的首尾,为回溯做数据准备。
        TreeNode[] left = order(root.left);
        TreeNode[] right = order(root.right);
        //对应情况1的无左孩子情况
        if (left == null) {
            root.right = right[0];
            return new TreeNode[]{root, right[1]};
        }
        //对应情况2的无右孩子情况
        if (right == null) {
            left[1].right = root;
            root.left = null;
            return new TreeNode[]{left[0], root};
        }
        //左右孩子都有
        left[1].right = root;
        root.left = null;
        root.right = right[0];
        //左右子树和父节点合并,这个合并返回是回溯的象征操作,自底向上,需要返回左子树的左和右子树的右,即首尾。
        return new TreeNode[]{left[0], right[1]};
    }

    //中序遍历本身的结果就是变为右子树的样子,所以记录前一个节点+中序改变树结构即可,用dummy节点来统一空树操作。
    TreeNode dummyRoot = new TreeNode(), p = dummyRoot;

    public TreeNode increasingBST2(TreeNode root) {
        if (root == null) return dummyRoot.right;

        increasingBST2(root.left);

        p.right = root;
        root.left = null;
        p = root;

        increasingBST2(root.right);

        return dummyRoot.right;
    }


    //Definition for a binary tree node.
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }
}

总结

1)回溯对于二叉树非常重要,它的核心在于自底向上合并子树,特殊(叶子)节点合并特殊化。
2)二叉树+回溯+栈+单向链表+dummyNode,五种关系较紧密。

参考文献

[1] LeetCode 原题

举报

相关推荐

0 条评论