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

ac

给定一颗二叉树,已知所有节点的值都不一样, 返回其中最大的且符合搜索二叉树条件的最大拓扑结构的大小。
拓扑结构是指树上的一个联通块。(非子树概念,是子结构的概念)

时间复杂度O(n^2)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

class TreeNode{
    TreeNode left;
    TreeNode right;
    int val;

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

public class Main {
    public static Scanner sc = new Scanner(System.in);

    public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static long mod = (long)Math.pow(2,29);

    public static void main(String[] args) throws Exception{
        String line;
        String[] strArr;
        line = reader.readLine();
        strArr = line.split(" ");
        int n = Integer.valueOf(strArr[0]);
        int rootVal = Integer.valueOf(strArr[1]);
        Map<Integer, TreeNode> mp = new HashMap<>(n);
        for (int i = 0; i < n; i++) {
            line = reader.readLine();
            strArr = line.split(" ");
            int val = Integer.valueOf(strArr[0]);
            int leftVal = Integer.valueOf(strArr[1]);
            int rightVal = Integer.valueOf(strArr[2]);

            if(!mp.containsKey(val)){
                mp.put(val, new TreeNode(val));
            }
            if(leftVal != 0){
                if(!mp.containsKey(leftVal)){
                    mp.put(leftVal, new TreeNode(leftVal));
                }
                mp.get(val).left = mp.get(leftVal);
            }
            if(rightVal != 0){
                if(!mp.containsKey(rightVal)){
                    mp.put(rightVal, new TreeNode(rightVal));
                }
                mp.get(val).right = mp.get(rightVal);
            }
        }
        TreeNode root = mp.get(rootVal);
        System.out.println(getMaxSearchTopo(root));
    }

    // 每个节点同样的求法
    static int getMaxSearchTopo(TreeNode root){
        if(root == null){
            return 0;
        }
        // 求以 root 为根的最大拓扑结构
        int max = 0;
        LinkedList<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode cur = queue.poll();
            if(isBSTNode(root, cur)){
                max++;
                if(cur.left != null) {
                    queue.add(cur.left);
                }
                if(cur.right != null) {
                    queue.add(cur.right);
                }
            }
        }
        max = Math.max(getMaxSearchTopo(root.left), max);
        max = Math.max(getMaxSearchTopo(root.right), max);
        return max;
    }

    // 判断 target是否符合BST预期
    // 比如 6 和 3 节点比较,依次是(6,3)(2, 3) (3, 3) 符合
    // 比如 6 和 20 节点比较,依次是(6,20)(12, 20) (13, 20) (16,20) (null, 20)不符合
    static boolean isBSTNode(TreeNode h ,TreeNode target){
        if(h == null){
            return false;
        }
        if(h == target){
            return true;
        }
        return isBSTNode(target.val < h.val ? h.left : h.right,target);
    }
}
/*
       6
    /     \
   2       12
  / \      / \
 1   3   10   13
        / \   / \
       7   8 20  16

12(10 13)
10 12(13 7 8)
10 12 13(7 8 20 16)
7 10 12 13(8 20 16) (8 在10的左边才行,但是8事实上在10的右边,8要被抛弃)
7 10 12 13(20 16)
7 10 12 13 16


11 6
6 2 12
2 1 3
1 0 0
3 0 0
12 10 13
10 7 8
7 0 0
8 0 0
16 0 0
13 20 16
20 0 0
*/

时间复杂度O(n * logn)

拓扑贡献记录 (左,右可以成为BST的数量)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.*;

class TreeNode{
    TreeNode left;
    TreeNode right;
    int val;

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

class Record{
    int l; // 左边贡献值
    int r; // 右边贡献值

    public Record(int l, int r) {
        this.l = l;
        this.r = r;
    }
}

public class Main {
    public static Scanner sc = new Scanner(System.in);

    public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static long mod = (long)Math.pow(2,29);

    public static void main(String[] args) throws Exception{
        String line;
        String[] strArr;
        line = reader.readLine();
        strArr = line.split(" ");
        int n = Integer.valueOf(strArr[0]);
        int rootVal = Integer.valueOf(strArr[1]);
        Map<Integer, TreeNode> mp = new HashMap<>(n);
        for (int i = 0; i < n; i++) {
            line = reader.readLine();
            strArr = line.split(" ");
            int val = Integer.valueOf(strArr[0]);
            int leftVal = Integer.valueOf(strArr[1]);
            int rightVal = Integer.valueOf(strArr[2]);

            if(!mp.containsKey(val)){
                mp.put(val, new TreeNode(val));
            }
            if(leftVal != 0){
                if(!mp.containsKey(leftVal)){
                    mp.put(leftVal, new TreeNode(leftVal));
                }
                mp.get(val).left = mp.get(leftVal);
            }
            if(rightVal != 0){
                if(!mp.containsKey(rightVal)){
                    mp.put(rightVal, new TreeNode(rightVal));
                }
                mp.get(val).right = mp.get(rightVal);
            }
        }
        TreeNode root = mp.get(rootVal);

        Map<TreeNode, Record> nodeRecordMap = new HashMap<>();
        int rs = dfs(root, nodeRecordMap);
        System.out.print(rs);
    }

    // 左右根,后序递归求拓扑贡献记录
    static int dfs(TreeNode root, Map<TreeNode, Record> nodeRecordMap){
        if(root == null){
            return 0;
        }
        // 以左,右为根的最大的bfs拓扑结构
        int ls = dfs(root.left, nodeRecordMap);
        int rs = dfs(root.right, nodeRecordMap);
        // 更新map,方便处理根
        modifyMap(root.left, root.val, nodeRecordMap, true);
        modifyMap(root.right, root.val, nodeRecordMap, false);
        // 得到左右的情况后,处理根的左右情况
        Record lr = nodeRecordMap.get(root.left);
        Record rr = nodeRecordMap.get(root.right);
        int lbst = lr == null ? 0 : lr.l + lr.r + 1;
        int rbst = rr == null ? 0 : rr.l + rr.r + 1;
        int rootAns = lbst + rbst + 1;
        nodeRecordMap.put(root, new Record(lbst, rbst));

        return Math.max(rootAns, Math.max(ls, rs));
    }

    static int modifyMap(TreeNode n, int v, Map<TreeNode, Record> m, boolean s){
        if(n == null ||  (!m.containsKey(n))){
            return 0;
        }
        Record r = m.get(n);
        // node小于起左节点 或者 大于其右边所有,那么是无用的,可以把左或右给删掉了
        if((s && n.val > v) || ((!s) && n.val < v)){
            m.remove(n);
            return r.l + r.r + 1;
        }else {
            // 否则需要重新设置下左或者右节点的record
            int minus = modifyMap(s ? n.right: n.left, v, m, s);
            if(s){
                r.r = r.r - minus;
            }else {
                r.l = r.l - minus;
            }
            m.put(n, r);
            return minus;
        }
    }

}
/*
               12(4,?)
            /       \
         10(3,0)      13(0,1)
        /          /      \
    4(1,1)       20(0,0)   16(0,0)
   /  \
2(0,0) 5(0,0)

    s
   /
   a
    \
     b
      \
       c
         \
          d
a,b,c都比s小,d比s大,那么

a,b,c左子树能贡献的左值,都能贡献给s
*/