算法22:二叉树各种算法——万能模板

二叉树有很多不同的算法,但是只要是涉及到二叉树算法的,绝大多数都可以套用一个固定的模板,写起来非常的爽。而且,算法越是复杂,模板越是显示威力

模板:

 //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        定义各种需要的变量
    }

    //套路入口方法
    public int mainMethod (Node head)
    {
        if (head == null) {
            return 0;
        }
       return process(head).height;
    }

    //套路核心方法
    public Info process(Node node)
    {
        //步骤1: 套路写法
        if (node == null) {
            return new Info(0);
        }

        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);

        //步骤2: 不同业务场景需要处理不同的业务逻辑
        
        
        //步骤3: 套路写法
        return new Info(height + 1);
    }

算法一:给定一个二叉树,找出其最大深度。 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
 说明: 叶子节点是指没有子节点的节点。
  示例:
 给定二叉树 [3,9,20,null,null,15,7],

    3
   / \
  9 20
  / \
 15 7
 返回它的最大深度 3

 

普通实现:

package code1.code_03;

/**
 * https://leetcode.cn/problems/maximum-depth-of-binary-tree
 */
public class Code04_MaxDepthOfBinaryTree {

    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;
        }
    }

    public static int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }


    public static void main(String[] args) {

    }
}

套用模板实现:

package code03.二叉树_02;

/**
 * 给定一个二叉树,找出其最大深度。
 * 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
 * 说明: 叶子节点是指没有子节点的节点。
 * 示例:
 * 给定二叉树 [3,9,20,null,null,15,7],
 *
 * 3
 * / \
 * 9 20
 * / \
 * 15 7
 * 返回它的最大深度 3
 */
public class Code04_TreeHeight {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        int height;
        Info (int height) {
            this.height = height;
        }
    }

    //套路入口方法
    public int maxDepth (Node head)
    {
        if (head == null) {
            return 0;
        }
       return process(head).height;
    }
    //套路核心方法
    public Info process(Node node)
    {
        //步骤1: 套路写法
        if (node == null) {
            return new Info(0);
        }

        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);

        //步骤2: 不同业务场景需要处理不同的业务逻辑
        int height = 0;
        if (leftInfo != null) {
            height = Math.max(leftInfo.height, height);
        }
        if (rightInfo != null) {
            height = Math.max(rightInfo.height, height);
        }

        //步骤3: 套路写法
        return new Info(height + 1);
    }

    public static void main(String[] args) {
        Code04_TreeHeight test = new Code04_TreeHeight();
        Node node = new Node(3);
        node.left = new Node(9);
        node.right = new Node(20);
        node.left.left = new Node(11);
        node.left.right = new Node(13);
        node.right.right = new Node(18);       //到此处,树的高度为3
        node.right.right.right = new Node(19); //到此处, 树的高度为4

        int height = test.maxDepth(node);
        System.out.println("树的高度为 :" + height);
    }
}

算法二:给定一棵二叉树的头节点head,返回这颗二叉树是不是满二叉树 。

回顾一下什么叫满二叉树,在一棵二叉树中, 所有的分支节点都存在左子树和右子树,并且所有叶子节点在同一层上, 这样的二叉树就是满二叉树

普通实现:

package code03.二叉树_02;

import java.util.LinkedList;
import java.util.Queue;
import java.util.zip.CheckedInputStream;

/**
 * 在一棵二叉树中, 所有的分支节点都存在左子树和右子树,并且所有叶子节点在同一层上
 * 这样的二叉树就是满二叉树
 */
public class Code05_FullTree {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //获取树的高度
    public int maxDepth(Node root) {
        if (root == null) {
            return 0;
        }
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }

    //获取整颗树的节点数
    public int nodes(Node node)
    {
        if (node == null) {
            return 0;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.add(node);
        int ans = 0;
        while (!queue.isEmpty()) {
            Node child = queue.poll();
            if (child.left != null) {
                queue.add(child.left);
            }
            if (child.right != null) {
                queue.add(child.right);
            }
            ans++;
        }
        return ans;
    }

    public boolean isFullTree (Node node) {
        if (node == null) {
            return true;
        }

        int heght = maxDepth(node);
        int nodeSize = nodes(node);
        //
        /**
         * 根据二叉树的性质,当二叉树的高度为k时
         * 那么整颗二叉树节点数最多为 2^k - 1
         * 因为此题判断是的满二叉树,因此判断节点个数即可
         */
        int size = (int) Math.pow(2, heght)-1;
        return nodeSize == size;
    }

    public static void main(String[] args) {
        Node node = new Node(3);
        node.left = new Node(9);
        node.right = new Node(20);
        //node.left.left = new Node(11);
        //node.left.right = new Node(13);
       // node.right.right = new Node(18);       //到此处,树的高度为3
        //node.right.right.right = new Node(19); //到此处, 树的高度为4

        Code05_FullTree test = new Code05_FullTree();
        boolean isFullTree = test.isFullTree(node);
        System.out.println(isFullTree);
    }
}

套用模板实现:

package code03.二叉树_02;

/**
 * 在一棵二叉树中, 所有的分支节点都存在左子树和右子树,并且所有叶子节点在同一层上
 * 这样的二叉树就是满二叉树
 */
public class Code05_01_FullTree {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        int height;
        boolean isFullTree;

        Info (int height, boolean isFull) {
            this.height = height;
            isFullTree = isFull;
        }
    }

    //套路入口方法
    public boolean isFullTree (Node head)
    {
        //我们默认,空树也是满二叉树
        if (head == null) {
            return true;
        }
        return process(head).isFullTree;
    }

    public Info process(Node node)
    {
        if (node == null) {
            return new Info(0, true);
        }

        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);

        //判断左、右子树是否是满二叉树, 有一个不是满二叉树,直接返回
        boolean isFullTree = leftInfo.isFullTree && rightInfo.isFullTree && leftInfo.height == rightInfo.height;
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;

        return new Info(height, isFullTree);
    }

    public static void main(String[] args) {
        Node node = new Node(3);
        node.left = new Node(9);
        node.right = new Node(20);
        node.left.left = new Node(11);
        node.left.right = new Node(13);
       // node.right.right = new Node(18);       //到此处,树的高度为3
        //node.right.right.right = new Node(19); //到此处, 树的高度为4

        Code05_01_FullTree test = new Code05_01_FullTree();
        boolean isFullTree = test.isFullTree(node);
        System.out.println(isFullTree);
    }
}

算法三:给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

package code03.二叉树_02;

/**
 * https://leetcode.cn/problems/balanced-binary-tree/
 * 给定一个二叉树,判断它是否是高度平衡的二叉树。
 *
 * 本题中,一棵高度平衡二叉树定义为:
 *
 * 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
 */
public class Code06_BalanceBinaryTree
{
    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;
        }
    }

    public static class Info {
        public boolean isBalanced;
        public int height;

        public Info(boolean i, int h) {
            isBalanced = i;
            height = h;
        }
    }

    public boolean isBalanced(TreeNode root) {
        return process(root).isBalanced;
    }

    public static Info process(TreeNode root) {
        //边界值
        if (root == null) {
            return new Info(true, 0);
        }

        Info leftInfo = process(root.left);
        Info rightInfo = process(root.right);
        //当前节点的高度
        int height = Math.max(leftInfo.height, rightInfo.height) + 1;
        boolean isBalanced = leftInfo.isBalanced && rightInfo.isBalanced
                && Math.abs(leftInfo.height - rightInfo.height) < 2;

        return new Info(isBalanced, height);
    }


    public static void main(String[] args) {
        Code06_BalanceBinaryTree tree = new Code06_BalanceBinaryTree();
        TreeNode node1 = tree.new TreeNode(3);
        TreeNode left2 = tree.new TreeNode(9);
        TreeNode righ2 = tree.new TreeNode(20);

        node1.left = left2;
        node1.right = righ2;

        TreeNode left3 = tree.new TreeNode(15);
        TreeNode righ3 = tree.new TreeNode(7);
        righ2.left = left3;
        righ2.right = righ3;

        System.out.println(tree.isBalanced(node1));
    }
}

算法四: 给定一棵二叉树的头节点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离。解释: 距离就是这2个节点间的数量,包含这两个节点本身

package code03.二叉树_02;

/**
 * 给定一棵二叉树的头节点head,任何两个节点之间都存在距离,
 * 返回整棵二叉树的最大距离
 *
 * 解释: 距离就是这2个节点间的数量,包含这两个节点本身
 */
public class Code07_MaxDIstance {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        int height;
        int maxDistance;    //记录当前节点的最大

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

    public int getMaxDistance (Node node)
    {
        return process(node).maxDistance;
    }

    public Info process(Node node)
    {
        if (node == null) {
            return new Info(0,0);
        }

        Info leftInto = process(node.left);
        Info rightInfo = process(node.right);

        //当前节点的高度
        int height = Math.max(leftInto.height, rightInfo.height) + 1;
        /**
         * 只经过左子树就产生最大距离, 距離為6
         *                3
         *            /     \
         *          4         5
         *       /    \
         *     41      42
         *       \      /
         *       412    421
         *                \
         *                4212
         *   产生最大距离的路径为  412 -> 41 -> 4 -> 42 ->421 -> 4212
         */
        int leftDistance = leftInto.maxDistance;

        /**
         * 只经过左子树就产生最大距离, 距離為6
         *                3
         *            /     \
         *          4         5
         *                  /    \
         *               51      52
         *                 \      /
         *                  512    521
         *                          \
         *                          5212
         *   产生最大距离的路径为  4512 -> 51 -> 5 -> 52 ->521 -> 5212
         */
        int rightDistance = rightInfo.maxDistance;


        /**
         * 只经过左子树就产生最大距离, 距離為5
         *                3
         *            /     \
         *          4         5
         *       /    \
         *     41      42
         *       \
         *       412
         *
         *   产生最大距离的路径为  412 -> 41 -> 4 -> 3 ->5
         */
        int totalDistance = leftInto.height + rightInfo.height + 1;

        //此处就是针对上方出现的3种情况做判断,找出怎么样组合才能产生最大距离
        int maxDistance = Math.max(Math.max(leftDistance, rightDistance), totalDistance);

        return new Info(height,maxDistance);
    }

    public static void main(String[] args) {

        Code07_MaxDIstance test = new Code07_MaxDIstance();
        Node node = new Node(3);
        node.left = new Node(4);
        node.right = new Node(5);
        //距离为3
        System.out.println("当前树的最大距离为 " + test.getMaxDistance(node));

        node.left.left = new Node(41);
        node.left.right = new Node(42);
        node.left.left.right = new Node(412);
        node.left.right.left = new Node(421);
        //正确答案为5
        System.out.println("当前树的最大距离为 " + test.getMaxDistance(node));

        node.right.right = new Node(52);
        node.right.right.right = new Node(522);
        node.right.right.right.left = new Node(5221);
        //正确答案为8
        System.out.println("当前树的最大距离为 " + test.getMaxDistance(node));
    }
}

算法五:判断二叉树是否是搜索二叉树

搜索二叉树 二叉排序树  二叉查找树 都是同一个概念,它或者是一颗空树,或者具有以下性质:
  1)若它的左子树不为空, 则左子树上的所有节点值均小于它的根节点
  2)若它的右子树不为空, 则右子树上的所有节点值均大于它的根节点
  3)它的左、右子树也分别是搜索二叉树
 

package code03.二叉树_02;

/**
 *判断二叉树是否是搜索二叉树
 *
 * 搜索二叉树 二叉排序树  二叉查找树 都是同一个概念,它或者
 * 是一颗空树,或者具有以下性质:
 * 1)若它的左子树不为空, 则左子树上的所有节点值均小于它的根节点
 * 2)若它的右子树不为空, 则右子树上的所有节点值均大于它的根节点
 * 3)它的左、右子树也分别为二叉排序树
 */
public class Code08_SearchBST {
    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        boolean ishBST;
        int max;
        int min;

        Info (boolean ishBST, int max, int min) {
            this.ishBST = ishBST;
            this.max = max;
            this.min = min;
        }
    }

    public boolean isSearchBST (Node node)
    {
        if (node == null) {
            return true;
        }
        return process(node).ishBST;
    }

    public Info process (Node node)
    {
        if (node == null) {
            return null;
        }

        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);

        //此处的max和min是为了返回上一侧使用
        //返回后,当前成就成了子节点。子节点也需要
        //是一颗搜索二叉树,即左节点值都小于根节点
        //有节点值都大于根节点
        int max = node.val;
        int min = node.val;
        //左树不为空
        if (leftInfo != null) {
            max = Math.max(leftInfo.max, max);
            min = Math.min(leftInfo.min, min);

        }
        if(rightInfo != null) {
            max = Math.max(rightInfo.max, max);
            min = Math.min(rightInfo.min, min);
        }

        boolean isBST = true;
        //它的左子树不为空, 则左子树上的所有节点值均小于它的根节点
        //它的左、右子树也分别为二叉排序树(搜索二叉树)
        if(leftInfo != null && (!leftInfo.ishBST || leftInfo.max >= node.val)) {
            isBST = false;
        }
        if(rightInfo != null && (!rightInfo.ishBST || rightInfo.min <= node.val)) {
            isBST = false;
        }

        return new Info(isBST, max, min);
    }

    public static void main(String[] args) {

        Code08_SearchBST test = new Code08_SearchBST();

        Node node = new Node(40);
        node.left = new Node(30);
        node.right = new Node(50);
        //true
        System.out.println("搜索二叉树 :" + test.isSearchBST(node));

        node.left.left = new Node(25);
        node.left.right = new Node(33);
        node.left.left.left = new Node(22);
        node.left.left.right = new Node(27);
        //true
        System.out.println("搜索二叉树 :" + test.isSearchBST(node));

        node.right.left = new Node(49);
        node.right.right = new Node(48);
        //false
        System.out.println("搜索二叉树 :" + test.isSearchBST(node));
    }
}

算法六: 给定一棵二叉树的头节点head, 返回这颗二叉树中最大的二叉搜索子树的大小

在算法五中我们刚刚实现了判断一颗树是否是二叉搜索树,而此题则整颗树可能是,也可能不是搜索二叉树。如果整颗树不是搜索二叉树,我们需要找到最大的子搜索二叉树节点数,如果整棵树是二叉搜索树,则返回整棵树的节点

package code03.二叉树_02;

/**
 * 给定一棵二叉树的头节点head,
 * 返回这颗二叉树中最大的二叉搜索子树的大小
 *
 * 搜索二叉树 二叉排序树  二叉查找树 都是同一个概念,它或者
 * 是一颗空树,或者具有以下性质:
 * 1)若它的左子树不为空, 则左子树上的所有节点值均小于它的根节点
 * 2)若它的右子树不为空, 则右子树上的所有节点值均大于它的根节点
 * 3)它的左、右子树也分别为二叉排序树
 */
public class Code09_SearchSubBST {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        boolean ishBST;
        int subBSTSize;
        int max;
        int min;

        Info (boolean ishBST, int max, int min, int subBSTSize) {
            this.ishBST = ishBST;
            this.max = max;
            this.min = min;
            this.subBSTSize = subBSTSize;
        }
    }

    public int subMaxBST (Node node)
    {
        if (node == null) {
            return 0;
        }
        return process(node).subBSTSize;
    }

    public Info process (Node node)
    {
        if (node == null) {
            return null;
        }

        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);

        //此处的max和min是为了返回上一侧使用
        //返回后,当前成就成了子节点。子节点也需要
        //是一颗搜索二叉树,即左节点值都小于根节点
        //有节点值都大于根节点
        int max = node.val;
        int min = node.val;

        //左树不为空
        if (leftInfo != null) {
            max = Math.max(leftInfo.max, max);
            min = Math.min(leftInfo.min, min);

        }
        if(rightInfo != null) {
            max = Math.max(rightInfo.max, max);
            min = Math.min(rightInfo.min, min);
        }

        boolean isBST = true;
        //左子搜索二叉树的节点数. 如果返回上一层无法组成新的二叉搜索树,则会一直
        //保留之前的二叉搜索树
        int leftSubBSTSize = leftInfo != null ? leftInfo.subBSTSize : 0;
        //右子搜索二叉树的节点数
        int rightSubBSTSize = rightInfo != null ? rightInfo.subBSTSize : 0;

        //检查当前节点,左节点,右节点是否可以组成新的二叉搜索树
        if(leftInfo != null && (!leftInfo.ishBST || leftInfo.max >= node.val)) {
            isBST = false;
        }
        if(rightInfo != null && (!rightInfo.ishBST || rightInfo.min <= node.val)) {
            isBST = false;
        }

        int subBSTSize = 0;
        //如果能够组成新的二叉搜索树
        if (isBST) {
            subBSTSize = leftSubBSTSize + rightSubBSTSize + 1;
        }
        else {
            //不能的话,左、右二叉搜索树选大的
            subBSTSize = Math.max(leftSubBSTSize, rightSubBSTSize);
        }

        return new Info(isBST, max, min, subBSTSize);
    }

    public static void main(String[] args) {

        Code09_SearchSubBST test = new Code09_SearchSubBST();

        Node node = new Node(40);
        node.left = new Node(20);
        node.right = new Node(80);
        //3
        System.out.println("搜索二叉树 :" + test.subMaxBST(node));

        node.left.left = new Node(26);
        node.left.right = new Node(30);
        node.left.left.left = new Node(19);
        node.left.left.right = new Node(27);

        node.left.right.left = new Node(22);
        node.left.right.right = new Node(38);
        node.left.right.left.left = new Node(21);
        node.left.right.left.right = new Node(23);
        //7
        System.out.println("搜索二叉树 :" + test.subMaxBST(node));
    }
}

继续针对算法六进行小范围的眼神题目

算法七 :给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的头节点

package code03.二叉树_02;

/**
 * 给定一棵二叉树的头节点head,
 * 返回这颗二叉树中最大的二叉搜索子树的头节点
 *
 * 搜索二叉树 二叉排序树  二叉查找树 都是同一个概念,它或者
 * 是一颗空树,或者具有以下性质:
 * 1)若它的左子树不为空, 则左子树上的所有节点值均小于它的根节点
 * 2)若它的右子树不为空, 则右子树上的所有节点值均大于它的根节点
 * 3)它的左、右子树也分别为二叉排序树
 */
public class Code10_SearchSubBST {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        boolean ishBST;
        int subBSTSize;
        int max;
        int min;
        Node head;

        Info (boolean ishBST, int max, int min, int subBSTSize, Node head) {
            this.ishBST = ishBST;
            this.max = max;
            this.min = min;
            this.subBSTSize = subBSTSize;
            this.head = head;
        }
    }

    public Node subHeadBST (Node node)
    {
        if (node == null) {
            return node;
        }
        return process(node).head;
    }

    public Info process (Node node)
    {
        if (node == null) {
            return null;
        }

        Info leftInfo = process(node.left);
        Info rightInfo = process(node.right);

        //此处的max和min是为了返回上一侧使用
        //返回后,当前成就成了子节点。子节点也需要
        //是一颗搜索二叉树,即左节点值都小于根节点
        //有节点值都大于根节点
        int max = node.val;
        int min = node.val;

        //左树不为空
        if (leftInfo != null) {
            max = Math.max(leftInfo.max, max);
            min = Math.min(leftInfo.min, min);

        }
        if(rightInfo != null) {
            max = Math.max(rightInfo.max, max);
            min = Math.min(rightInfo.min, min);
        }

        boolean isBST = true;
        //左子搜索二叉树的节点数. 如果返回上一层无法组成新的二叉搜索树,则会一直
        //保留之前的二叉搜索树
        int leftSubBSTSize = leftInfo != null ? leftInfo.subBSTSize : 0;
        //右子搜索二叉树的节点数
        int rightSubBSTSize = rightInfo != null ? rightInfo.subBSTSize : 0;

        //检查当前节点,左节点,右节点是否可以组成新的二叉搜索树
        if(leftInfo != null && (!leftInfo.ishBST || leftInfo.max >= node.val)) {
            isBST = false;
        }
        if(rightInfo != null && (!rightInfo.ishBST || rightInfo.min <= node.val)) {
            isBST = false;
        }

        int subBSTSize = 0;
        Node head = null;
        //如果能够组成新的二叉搜索树
        if (isBST) {
            subBSTSize = leftSubBSTSize + rightSubBSTSize + 1;
            //如果当前节点和左右子树可以组成新的搜索二叉子树, 则当前节点为新的头结点
            head = node;
        }
        else {
            //不能的话,左、右二叉搜索树选大的
            subBSTSize = Math.max(leftSubBSTSize, rightSubBSTSize);
            head = leftSubBSTSize > rightSubBSTSize ? leftInfo.head : rightInfo.head;
        }

        return new Info(isBST, max, min, subBSTSize, head);
    }

    public static void main(String[] args) {

        Code10_SearchSubBST test = new Code10_SearchSubBST();

        Node node = new Node(40);
        node.left = new Node(20);
        node.right = new Node(80);
        //头结点为40
        Node head = test.subHeadBST(node);
        System.out.println(head.val);

        //node.left.left = new Node(26);
        node.left.left = new Node(18);

        node.left.right = new Node(30);
        node.left.left.left = new Node(15);
        node.left.left.right = new Node(27);

        //node.left.right.left = new Node(22);
        node.left.right.left = new Node(22);

        node.left.right.right = new Node(38);
        node.left.right.left.left = new Node(21);
        node.left.right.left.right = new Node(23);
        //头结点为30
        head = test.subHeadBST(node);
        System.out.println(head.val);

        //把节点值26改成18, 则新的头结点则是30
        head = test.subHeadBST(node);
        System.out.println(head.val);

        //把节点值22改成31, 则新的头结点则是18
        head = test.subHeadBST(node);
        System.out.println(head.val);

    }
}

继续套用模板来解决最小公共祖先的问题

算法八: 给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先。解释一下什么叫公共祖先,公共祖先就是这两个节点第一次连接在一起的节点。

解题思路:

1)首先得找到这两个节点

2)第一次找到以后,记录下这个节点,逐层往上返回即可

package code03.二叉树_02;

/**
 * 给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先
 */
public class Code11_MinSameParents {

    static class Node {
        int val;
        Node left;
        Node right;

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

    //套路类,辅助收集树的信息. 这个辅助类非常重要,可以封装各种各样的信息
    static class Info {
        boolean findA;
        boolean findB;
        Node minParents;  //最小公共祖先

        Info (Node minParents, boolean findA, boolean findB) {
            this.minParents = minParents;
            this.findA = findA;
            this.findB = findB;
        }
    }

    public Node minParents(Node head, Node a, Node b)
    {
        if (head == null || a == null || b == null) {
            return null;
        }
        return process(head, a, b).minParents;
    }

    public Info process(Node head, Node a, Node b)
    {
        if (head == null) {
            return new Info(null, false, false);
        }

        Info leftInfo = process(head.left, a, b);
        Info rightInfo = process(head.right, a, b);

        Node minParent = leftInfo.minParents;
        //判断最小公共父节点,首先得找到这两个节点
        boolean findA = head == a || leftInfo.findA || rightInfo.findA;
        boolean findB = head == b || leftInfo.findB || rightInfo.findB;

        //如果同时找到了a和b节点,那么检查他们的最小公共
        //父节点是否已经找到,没有找到的话则记录下来
        //如果已经找到最小公共祖先,则一直返回
        if (findA && findB && minParent == null) {
            minParent = head;
        }
        return new Info(minParent, findA, findB);
    }

    public static void main(String[] args)
    {
        Code11_MinSameParents test = new Code11_MinSameParents();
        Node node = new Node(0);
        Node node1 = new Node(11);
        Node node2 = new Node(22);
        Node node3 = new Node(44);
        Node node4 = new Node(16);
        Node node5 = new Node(32);
        Node node6 = new Node(67);
        Node node7= new Node(88);
        Node node8 = new Node(76);

        node.left = node1; node.right = node2;
        node1.left = node3; node1.right = node4;
        node3.left = node5;
        node5.right = node6;
        node2.right = node7; node7.left = node8;

        /**
         * 构造一颗二叉树
         *               0
         *            /     \
         *         11        22
         *       /    \        \
         *     44      16       88
         *    /                /
         *   32              76
         *     \
         *      67
         *
         */
        //node4对应16, node6对应67. 应该找到的最小公共节点值为11
        Node minP = test.minParents(node, node4, node6);
        System.out.println(minP != null ? minP.val : null);

        //node6对应67, node8对应76. 应该找到的最小公共节点值为0
        minP = test.minParents(node, node8, node6);
        System.out.println(minP != null ? minP.val : null);

        //测试两个相同节点  node5对应32,应该找到32
        minP = test.minParents(node, node5, node5);
        System.out.println(minP != null ? minP.val : null);

        //测试一个子节点,一个父节点.
        // 父节点node3对应44,子节点node5对应32,应该找到node3即值44
        minP = test.minParents(node, node5, node3);
        System.out.println(minP != null ? minP.val : null);
    }
}

相信看了这么多道题目以后,是否非常认可我的模板套路,越是复杂的二叉树业务,模板套路越是能够发挥出强大的威力。说是万能模板,肯定是夸张了,但是这种模板化的写法确实非常的实用,能够适应很多二叉树的算法,抓紧掌握吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值