二叉树的递归套路后续

234 阅读4分钟

「这是我参与2022首次更文挑战的第34天,活动详情查看:2022首次更文挑战」。

一、二叉树中最大的搜索二叉树的大小

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

1、分析

一颗二叉树不一定就是搜索二叉树,但它的子树是二叉搜索树,求它的子树是二叉搜索树的大小

目标:x树上BST子树上的maxSize

x不做头:

  • x左树上的maxBSTSize
  • X右树上的maxBSTSize

x做头:x做头的maxBSTSize

  • x左树是BST
  • x右树是BST
  • x左树的最大值 < x
  • x右树的最小值 > x
  • x左树size + x右树size + 1

如果maxBSTSize == size,则是BST,省掉BST变量

2、实现

public static class Node {
    public int value;
    public Node left;
    public Node right;

    public Node(int data) {
        this.value = data;
    }
}

public static class Info {
    public int maxBSTSubtreeSize;
    public int allSize;
    public int max;
    public int min;

    public Info(int m, int a, int ma, int mi) {
        maxBSTSubtreeSize = m;
        allSize = a;
        max = ma;
        min = mi;
    }
}

public static int maxSubBSTSize(Node head) {
    if (head == null) {
        return 0;
    }
    return process(head).maxBSTSubtreeSize;
}

private static Info process(Node x) {
    if (x == null) {
        return null;
    }
    Info leftInfo = process(x.left);
    Info rightInfo = process(x.right);
    int max = x.value;
    int min = x.value;
    int allSize = 1;
    if (leftInfo != null) {
        max = Math.max(max, leftInfo.max);
        min = Math.min(min, leftInfo.min);
        allSize += leftInfo.allSize;
    }
    if (rightInfo != null) {
        max = Math.max(max, rightInfo.max);
        min = Math.min(min, rightInfo.min);
        allSize += rightInfo.allSize;
    }
    int p1 = -1; // 可能性一
    if (leftInfo != null) {
        p1 = Math.max(p1, leftInfo.maxBSTSubtreeSize);
    }
    int p2 = -1; // 可能性二
    if (rightInfo != null) {
        p2 = Math.max(p2, rightInfo.maxBSTSubtreeSize);
    }
    int p3 = -1; // 可能性三
    boolean leftBST = leftInfo == null ? true : leftInfo.maxBSTSubtreeSize == leftInfo.allSize;
    boolean rightBST = rightInfo == null ? true : rightInfo.maxBSTSubtreeSize == rightInfo.allSize;
    if (leftBST && rightBST) {
        boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.value);
        boolean rightMinMoreX = rightInfo == null ? true : (rightInfo.min > x.value);
        if (leftMaxLessX && rightMinMoreX) {
            int leftSize = leftInfo == null ? 0 : leftInfo.allSize;
            int rightSize = rightInfo == null ? 0 : rightInfo.allSize;
            p3 = leftSize + rightSize + 1;
        }
    }
    return new Info(Math.max(p1, Math.max(p2, p3)), allSize, max, min);
}

二、二叉树中最大的二叉搜索树的头节点

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

1、分析

x无关:

  • x左树maxBSTNode
  • x右树maxBSTNode

x有关:

  • x左树max < x
  • x右树min > x
  • x是头节点,x.left == x左树的maxBSTNode && x.right == x右树的maxBSTNode

2、实现

public static class Node {
    public int value;
    public Node left;
    public Node right;

    public Node(int data) {
        this.value = data;
    }
}

public static class Info {
    public Node maxSubBSTHead;
    public int maxSubBSTSize;
    public int min;
    public int max;

    public Info(Node h, int size, int mi, int ma) {
        maxSubBSTHead = h;
        maxSubBSTSize = size;
        min = mi;
        max = ma;
    }
}

public static Node maxSubBSTHead(Node head) {
    if (head == null) {
        return null;
    }
    return process(head).maxSubBSTHead;
}

private static Info process(Node X) {
    if (X == null) {
        return null;
    }
    Info leftInfo = process(X.left);
    Info rightInfo = process(X.right);
    int min = X.value;
    int max = X.value;
    Node maxSubBSTHead = null;
    int maxSubBSTSize = 0;
    if (leftInfo != null) {
        min = Math.min(min, leftInfo.min);
        max = Math.max(max, leftInfo.max);
        maxSubBSTHead = leftInfo.maxSubBSTHead;
        maxSubBSTSize = leftInfo.maxSubBSTSize;
    }
    if (rightInfo != null) {
        min = Math.min(min, rightInfo.min);
        max = Math.max(max, rightInfo.max);
        if (rightInfo.maxSubBSTSize > maxSubBSTSize) {
            maxSubBSTHead = rightInfo.maxSubBSTHead;
            maxSubBSTSize = rightInfo.maxSubBSTSize;
        }
    }
    if ((leftInfo == null ? true : (leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.value))
        && (rightInfo == null ? true : (rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.value))) {
        maxSubBSTHead = X;
        maxSubBSTSize = (leftInfo == null ? 0 : leftInfo.maxSubBSTSize)
            + (rightInfo == null ? 0 : rightInfo.maxSubBSTSize) + 1;
    }
    return new Info(maxSubBSTHead, maxSubBSTSize, min, max);
}

三、返回二叉树中a和b的最低公共祖先

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

1、分析

最低公共祖先:一个节点往上跑,另一个节点也往上跑,它们在哪个节点汇聚问题

方法一:遍历每个节点的时候,把每个节点和它的父节点存入HashMap中,key:当前节点,value:当前节点的父节点。然后a节点往上走(从map中获取a的父节点),沿途把a这条线上的所有节点都放入Set中,然后b再往上一直走,如果b这条线上的某个节点存在Set中,则此时就是a和b的最低公共祖先

方法二:二叉树的递归套路

x无关:x不是最低汇聚点

  • x的左树上有答案,a和b在x的左树上有汇聚点
  • x的右树上有答案,a和b在x的右树上有汇聚点
  • x整颗树上,a和b没找全

x有关:x是最低汇聚点

  • x的左树发现了a和b其中一个,x的右树发现了a和b其中一个
  • x本身就是a,x的左树或右树发现了b
  • x本身就是b,x的左树或右树发现了a

信息收集:

这棵树上有没有发现a

这颗树上有没有发现b

这颗树上有没有发现a和b的汇聚点

2、实现

public static class Node {
    public int value;
    public Node left;
    public Node right;

    public Node(int data) {
        this.value = data;
    }
}

public static Node lowestAncestor(Node head, Node a, Node b) {
    return process(head, a, b).ans;
}

private static Info process(Node x, Node a, Node b) {
    if (x == null) {
        return new Info(false, false, null);
    }
    Info leftInfo = process(x.left, a, b);
    Info rightInfo = process(x.right, a, b);
    boolean findA = (x == a) || leftInfo.findA || rightInfo.findA;
    boolean findB = (x == b) || leftInfo.findB || rightInfo.findB;
    Node ans = null;
    if (leftInfo.ans != null) {
        ans = leftInfo.ans;
    } else if (rightInfo.ans != null) {
        ans = rightInfo.ans;
    } else {
        if (findA && findB) {
            ans = x;
        }
    }
    return new Info(findA, findB, ans);
}