MENU

树形DP

August 15, 2018 • Read: 183 • 算法

从五道题来看树形DP

1.求树的最大值和最小值

假设现在有一棵树,我只要求出每个结点作为头节点对应子树的最大值和最小值,那么最终答案一定在其中,因此每个结点都有两个信息,最大值和最小值,我把这个信息封装为一个结构体,带入递归中,就能求出最终答案,最大值就等于当前结点左子树的最大值和右子树的最大值和当前结点的值三者中最大的那一个,最小值也是三者中最小的那一个。

public class Main {    
    class Node {
        int value;
        Node left;
        Node right;
        Node(int value) {
            this.value = value;
        }
    }
    class Data {
        int max,min;
        Data(int max,int min) {
            this.max = max;
            this.min = min;
        }
    }
    public Data process(Node head) {
        if(head == null)
            return new Data(Integer.MIN_VALUE,Integer.MAX_VALUE);
        Data leftData = process(head.left);
        Data rightData = process(head.right);
        return new Data(Math.max(Math.max(leftData.max,rightData.max),head.value),
                        Math.min(Math.min(leftData.min,rightData.min),head.value));
    }
}
2.求最大搜索二叉树的大小

这道题具体题意是说,给一棵树(任意一棵树,不一定是搜索二叉树),其子树有可能是一棵搜索二叉树,返回整棵树中最大搜索二叉树的大小

假设当前遍历到的结点是node,最大二叉搜索树的大小应该是node左子树最大二叉搜索树的大小、node右子树最大二叉搜索树的大小、以node为头结点的最大二叉搜索树的大小,三者中最大的那个。只有满足node左子树的头结点等于node的左孩子、node右子树的头结点等于node的右孩子、node.value大于左子树的最大值、node.value小于右子树的最小值这四个条件,才能使得node左右子树都是二叉搜素树的情况下,加上node依然能够构成二叉搜索树。因此结构体中存的信息应该有最大值、最小值、头节点以及大小

public class Main {    
    class Data {
        int max,min,size;
        Node head;
        Data(int size,Node head,int min,int max) {
            this.size = size;
            this.head = head;
            this.max = max;
            this.min = min;
        }
    }
    public Data process(Node head) {
        if(head == null)
            return new Data(0,null,Integer.MAX_VALUE,Integer.MIN_VALUE);
        Data leftData = process(head.left);
        Data rightData = process(head.right);
        
        int leftSize = leftData.size;
        int rightSize = rightData.size;
        Node leftHead = leftData.head;
        Node rightHead = rightData.head;
        int leftMax = leftData.max;
        int leftMin = leftData.min;
        int rightMax = rightData.max;
        int rightMin = rightData.min;
        
        int includeHeadSize = 0;
        if(leftHead == head.left &&
           rightHead == head.right &&
           head.value > leftData.max && 
           head.value < rightData.min)
            includeHeadSize = leftSize + rightSize + 1;
        
        int maxSize = Math.max(Math.max(leftSize,rightSize),includeHeadSize);
        Node maxHead = leftSize > rightSize ? leftHead : rightHead;
        if(maxSize == includeHeadSize)
            maxHead = head;
        return new Data(maxSize,maxHead,
                        Math.min(Math.min(leftMin,rightMin),head.value),
                        Math.max(Math.max(leftMax,rightMax),head.value));
    }
}
3.求一棵二叉树上的最远距离

二叉树中,一个节点可以往上走和往下走,那么从节点A总能走到结点B,结点A走到结点B的距离为:A走到B最短路径上的结点个数。求一棵二叉树的最远距离。

只要求出每一个结点为头的整棵树最大距离,答案一定在其中。对于一个结点来说,最大距离可能分为两种情况,经过我这个结点不经过我这个结点,不经过我这个结点又分为两种情况:左子树的最大距离右子树的最大距离中较大的那个。对于下面的图来说,当前结点是1,那么他的最大距离就是不经过1这个结点做右子树距离最大的那个,答案是8

那么经过当前结点的距离就应该是,左子树的深度+右子树的深度+1,分析了全部的情况,我们就把需要的信息包含在结构体中即可

public class Main {
    class Data {
        int maxDistance,h;
        Data(int maxDistance,int h) {
            this.maxDistance = maxDistance;
            this.h = h;
        }
    }
    public Data process(Node head) {
        if(head == null)
            return new Data(0,0);
        Data leftData = process(head.left);
        Data rightData = process(head.right);
        //三种可能性
        int leftDistance = leftData.maxDistance;
        int rightDistance = rightData.maxDistance;
        int includeHeadDistace = leftData.h + 1 + rightData.h;
        
        int maxSize = Math.max(Math.max(leftDistance,rightDistance),includeHeadDistace);
        int maxH = Math.max(leftData.h,rightData.h) + 1;
        return new Data(maxSize,maxH);
    }
}
4.LeetCode337.打家劫舍 III


假设现在遍历到结点x1,x1分别是x2和x3的直接父结点,那么对于x1来说有两种选择,抢或者不抢。如果抢,那么价值就是x1的价值加上x2、x3不抢的价值;如果不抢,那么价值就是x2抢或不抢中最大的加上x3抢或不抢中最大的。所以我们需要封装的信息有,抢某个结点的价值和不抢不某个结点的价值

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    class Data {
        int robber_prices,no_robber_prices;
        Data(int robber_prices,int no_robber_prices) {
            this.robber_prices = robber_prices;
            this.no_robber_prices = no_robber_prices;
        }
    }
    public Data process(TreeNode head) {
        if(head == null)
            return new Data(0,0);
        int robber_prices = head.val;
        int no_robber_prices = 0;
        //首先遍历左孩子
        Data leftData = process(head.left);
        robber_prices += leftData.no_robber_prices;
        no_robber_prices += Math.max(leftData.no_robber_prices,leftData.robber_prices);
        //然后遍历右孩子
        Data rightData = process(head.right);
        robber_prices += rightData.no_robber_prices;
        no_robber_prices += Math.max(rightData.no_robber_prices,rightData.robber_prices);
        
        return new Data(robber_prices,no_robber_prices);
    }
    public int rob(TreeNode root) {
        Data res = process(root);
        return Math.max(res.robber_prices,res.no_robber_prices);
    }
}
5.LeetCode110.平衡二叉树

直接点击链接,这道题在我的另一篇文章里讲了

总结

树本身就是一个天然的递归结构,dp本身也就用到递归的思想,树形DP难在将所有的信息考虑全,普通的DP难在递归方程式怎么写

最后编辑于: October 7, 2018
Archives Tip
QR Code for this page
Tipping QR Code