MENU

树形 DP

August 15, 2018 • Read: 3262 • 算法阅读设置

从五道题来看树形 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 难在递归方程式怎么写

Last Modified: October 7, 2018
Archives Tip
QR Code for this page
Tipping QR Code