首页 > 试题广场 >

找到二叉树中符合搜索二叉树条件的最大拓扑结构

[编程题]找到二叉树中符合搜索二叉树条件的最大拓扑结构
  • 热度指数:1491 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一颗二叉树,已知所有节点的值都不一样, 返回其中最大的且符合搜索二叉树条件的最大拓扑结构的大小。
拓扑结构是指树上的一个联通块。

输入描述:
第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。

以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)

ps:节点的编号就是节点的值。


输出描述:
输出一个整数表示满足条件的最大拓扑结构的大小。
示例1

输入

3 2
2 1 3
1 0 0
3 0 0

输出

3

备注:

用左神提的“拓扑贡献记录”来对问题进行求解。我们需要对整颗树进行深度优先遍历,当遍历到最底层节点时(base case),就开始逐步往上层返回信息:如果以当前节点为根,形成的BST包含多少个节点。上层节点拿到左右孩子的信息后需要检查自己的节点值是否能大于左孩子最右的节点值,不能到达的节点就需要从贡献记录中移除这个节点贡献的节点数;还需要检查自己的节点值是否小于右孩子的最左节点值,不能达到的节点也需要从贡献记录中删掉其贡献的节点数。思路说出来好像很容易,但真是很难想啊,而且这个思路的coding难度也很大,修改贡献记录时还得把要删除的节点数逐层往上返,给上层的所有节点减掉
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.HashMap;

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

// 拓扑贡献记录
class Record {
    public int left;       // 左孩子贡献的BST节点数
    public int right;      // 右孩子贡献的BST节点数
    public Record(int left, int right) {
        this.left = left;
        this.right = right;
    }
}

public class Main{
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        HashMap<Integer, TreeNode> map = new HashMap<>();
        String[] params = br.readLine().split(" ");
        int n = Integer.parseInt(params[0]), rootVal = Integer.parseInt(params[1]);
        // 构建二叉树
        TreeNode root = new TreeNode(rootVal);
        map.put(rootVal, root);
        for(int i = 0; i < n; i++){
            params = br.readLine().split(" ");
            int nodeVal = Integer.parseInt(params[0]);
            int leftVal = Integer.parseInt(params[1]);
            int rightVal = Integer.parseInt(params[2]);
            TreeNode node = map.get(nodeVal);
            if(leftVal != 0) {
                node.left = new TreeNode(leftVal);
                map.put(leftVal, node.left);
            }
            if(rightVal != 0) {
                node.right = new TreeNode(rightVal);
                map.put(rightVal, node.right);
            }
        }
        // 求解
        System.out.println(maxBstTopoSize(root));
    }
    
    private static int maxBstTopoSize(TreeNode head) {
        HashMap<TreeNode, Record> map = new HashMap<>();      // 用于存储各个节点的拓扑贡献记录
        return postOrder(head, map);
    }
    
    private static int postOrder(TreeNode head, HashMap<TreeNode, Record> map) {
        if(head == null) return 0;
        int leftSize = postOrder(head.left, map);
        int rightSize = postOrder(head.right, map);
        // 检查头结点能够囊括左右孩子多少节点,并修改孩子节点的贡献记录
        modifyMap(head.left, head.val, map, true);
        modifyMap(head.right, head.val, map, false);
        // 获得左右孩子的贡献记录
        Record leftRecord = map.get(head.left);
        Record rightRecord = map.get(head.right);
        // 计算左右孩子贡献的BST节点数
        int leftBST = leftRecord == null? 0: leftRecord.left + leftRecord.right + 1;
        int rightBST = rightRecord == null? 0: rightRecord.left + rightRecord.right + 1;
        map.put(head, new Record(leftBST, rightBST));
        return Math.max(leftBST + rightBST + 1, Math.max(leftSize, rightSize));
    }
    
    public static int modifyMap(TreeNode node, int rootVal, HashMap<TreeNode, Record> map, boolean isLeftTree) {
        if(node == null || (!map.containsKey(node))) return 0;
        Record record = map.get(node);      // 获得当前节点node的拓扑贡献记录
        if((isLeftTree && node.val > rootVal) || ((!isLeftTree) && node.val < rootVal)){
            // 如果左树的右边界节点node比根的值大,或者右树的左边界节点node比根的值小,就移除node的贡献
            map.remove(node);
            return record.left + record.right + 1;       // 要把node节点及其孩子节点的贡献返回去让上层节点删除掉
        }else{
            // 是左树就递归检查右边界,是右树就递归检查左边界
            int minus = modifyMap(isLeftTree? node.right: node.left, rootVal, map, isLeftTree);
            // 沿途修改边界节点node的贡献记录
            if(isLeftTree){
                record.right = record.right - minus;
            }else{
                record.left = record.left - minus;
            }
            map.put(node, record);
            return minus;
        }
    }
}

编辑于 2021-12-07 15:32:52 回复(0)