Loading

树形dp套路合集:找到二叉树中的最大搜索二叉子树 & 判断二叉树是否为平衡二叉树 & 二叉树节点间的最大距离问题

找到二叉树中的最大搜索二叉子树

题目:找到二叉树中的最大搜索二叉子树

《程序员代码面试指南》第38题 P121 难度:尉★★☆

书上原话:“本题涉及二叉树面试题中一个很常见的套路,也是全书的一个重要内容”。可见其重要性。

这个套路的名字叫做树形dp套路

树形dp套路使用前提:如果题目求解目标是S规则,则求解流程可以定成以每一个节点为头结点的子树在S规则下的每一个答案,并且最终答案一定在其中。

以本题为例,求解流程可以定成:在整棵二叉树中,求出每一个节点为头结点的子树的最大搜索二叉子树(对任何一棵子树都求出答案),并且最终答案(整棵二叉树的最大搜索二叉子树)一定在其中。

树形dp套路第一步:以某个节点X为头结点的子树中,分析答案有哪些可能性,并且这种分析是以X的左子树、X的右子树和X整棵树的角度来考虑可能性的。

以本题举例,包含三种可能性。概括而言,最大搜索二叉子树可能来自左子树右子树,或者是用X连起左子树和右子树所构成的整体

树形dp套路第二步:根据第一步的可能性分析,列出所有需要的信息。

以本题举例,左树上需要的信息为leftMaxBSTHeadleftBSTSizeleftMax右树上需要的信息为rightMaxBSTHeadrightBSTSizerightMin

树形dp套路第三步,合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构。

以本题举例,合并成包含maxBSTHeadmaxBSTSizemaxminReturnType类。需要通过它们来判断第一步中的三种可能性。

public class ReturnType {
    public Node maxBSTHead;
    public int maxBSTSize;
    public int min;
    public int max;

    public ReturnType(Node maxBSTHead, int maxBSTSize, int min, int max) {
        this.maxBSTHead = maxBSTHead;
        this.maxBSTSize = maxBSTSize;
        this.min = min;
        this.max = max;
    }
}

树形dp套路第四步:设计递归函数,递归函数是处理以X为头结点的情况下的答案,包括

  1. 设计递归的base case(本题中即为空树的情况)
  2. 直接得到左树和右树的所有信息
  3. 把可能性做整合
  4. 返回第三步的信息结构

代码如下:

public ReturnType process(Node X) {
    // base case : 如果子树是空树
    // 最小值为系统最大
    // 最大值为系统最小
    if (X == null) {
        return new ReturnType(null, 0, Integer.MAX_VALUE, Integer.MIN_VALUE);
    }
    // 默认直接得到左树全部信息
    ReturnType lData = process(X.left);
    // 默认直接得到右树全部信息
    ReturnType rData = process(X.right);
    // 以下过程为信息整合
    // 同时以X为头的子树也做同样的要求,也需要返回如ReturnType描述的全部信息
    // 以X为头的子树的最小值是:左树最小、右树最小、X的值,三者中最小的
    int min = Math.min(X.value, Math.min(lData.min, rData.min));
    // 以X为头的子树的最大值是:左树最大、右树最大、X的值,三者中最大的
    int max = Math.max(X.value, Math.max(lData.max, rData.max));
    // 如果只考虑可能性一和可能性二,以X为头的子树的最大搜索二叉树大小
    int maxBSTSize = Math.max(lData.maxBSTSize, rData.maxBSTSize);
    // 如果只考虑可能性一和可能性二,以X为头的子树的最大搜索二叉树头节点
    Node maxBSTHead = lData.maxBSTSize >= rData.maxBSTSize ? lData.maxBSTHead
        : rData.maxBSTHead;
    // 利用收集的信息,可以判断是否存在可能性三
    if (lData.maxBSTHead == X.left && rData.maxBSTHead == X.right
        && X.value > lData.max && X.value < rData.min) {
        maxBSTSize = lData.maxBSTSize + rData.maxBSTSize + 1;
        maxBSTHead = X;
    }
    // 信息全部搞定,返回
    return new ReturnType(maxBSTHead, maxBSTSize, min, max);
}

树形dp套路就是以上四个步骤,就是利用递归函数设计一个二叉树后序遍历的过程先遍历左子树收集信息,然后是右子树收集信息,最后在头节点做信息整合。因为是递归函数,所以对所有的子树要求一样,都返回ReturnType的实例。依次求出每棵子树的答案,总答案一定在其中。主方法如下:

public Node getMaxBST(Node head) {
    return process(head).maxBSTHead;
}

详细解析见书P122-124。(第一次做这种树形dp套路的题,书上说后面还有一些题是用这种套路来解题,待我做到后面再多加熟练熟练)

----------------------------------------------------------------------------------------------------------------------------

(2022年1月30日10:25:39 更新)

判断二叉树是否为平衡二叉树

题目:判断二叉树是否为平衡二叉树

《程序员代码面试指南》第44题 P146 难度:士★☆☆

此题为树形dp套路的第2题,较为简单,一下就想到思路。

首先,树形dp套路的前提是满足的,依次考查每个节点为头节点的子树,如果都是平衡二叉树,那么整体就是平衡二叉树

树形dp套路步骤不再叙述,见上题。

本题中,第一步即有4种可能性,前3种为不平衡:①左子树不平衡右子树不平衡左右子树的高度差超过1;最后一种就是剩下的一种情况,为平衡二叉树:④左右子树都平衡且高度差不超过1

第二步得出需要知道左右子树是否平衡,以及它们的高度差这些信息。

根据第二步,第三步得出ReturnType

public class ReturnType {
    public boolean isBalanced;
    public int height;

    public ReturnType(boolean isBalanced, int height) {
        this.isBalanced = isBalanced;
        this.height = height;
    }
}

第四步,设计递归函数

整体代码如下:

public ReturnType process(Node head) {
    if (head == null) {
        return new ReturnType(true, 0);
    }
    ReturnType leftData = process(head.left);
    ReturnType rightData = process(head.right);
    int height = Math.max(leftData.height, rightData.height) + 1;
    boolean isBalanced = leftData.isBalanced && rightData.isBalanced
        && Math.abs(leftData.height - rightData.height) < 2;
    return new ReturnType(isBalanced, height);
}

public boolean isBalanced(Node head) {
    return process(head).isBalanced;
}

----------------------------------------------------------------------------------------------------------------------------

(2022年2月18日10:26:06 更新)

二叉树节点间的最大距离问题

题目:二叉树节点间的最大距离问题

《程序员代码面试指南》第51题 P168 难度:尉★★☆

此题为树形dp套路的第3题,不小心看到了解答用的树形dp套路,没办法就顺着往下想了。知道是树形dp套路后还是很容易的。

树形dp套路前提是满足的:依次求出每一个节点为头节点的子树上的最大距离最终答案一定在其中

树形dp套路第一步以某个节点X为头节点的子树中,分析答案来自哪些可能性……

可能性有3个:最大距离可能是 ①左子树上的最大距离右子树上的最大距离左子树高度+右子树高度+1

树形dp套路第二步列出所有需要的信息,即子树上的最大距离以及高度

树形dp套路第三步:定义ReturnType

public class ReturnType {
    public int maxDistance;
    public int height;

    public ReturnType(int maxDistance, int height) {
        this.maxDistance = maxDistance;
        this.height = height;
    }
}

树形dp套路第四步设计递归函数(具体步骤第一题已经叙述过)

代码如下:

public ReturnType process(Node head) {
    if (head == null) {
        return new ReturnType(0, 0);
    }
    ReturnType leftData = process(head.left);
    ReturnType rightData = process(head.right);
    int height = Math.max(leftData.height, rightData.height) + 1;
    int maxDistance = Math.max(leftData.height + rightData.height + 1,
                               Math.max(leftData.maxDistance, rightData.maxDistance));
    return new ReturnType(maxDistance, height);
}

public int getMaxDistance(Node head) {
    return process(head).maxDistance;
}
posted @ 2022-01-24 12:38  幻梦翱翔  阅读(56)  评论(0)    收藏  举报