树形dp问题套路

news/2024/7/24 13:36:00

请添加图片描述
⭐️前言⭐️

本篇文章旨在将二叉树中的树形dp问题模板化,借助信息体传递的方式,通解树形dp问题。

🍉欢迎点赞 👍 收藏留言评论 📝私信必回哟😁

🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言

🍉博客中涉及源码及博主日常练习代码均已上传GitHub


请添加图片描述

📍内容导读📍

  • 🍅递归套路
  • 🍅判断二叉树是不是平衡二叉树
  • 🍅判断二叉树是不是搜索二叉树
  • 🍅二叉树最大直径
  • 🍅判断二叉树是不是满二叉树
  • 🍅最大二叉搜索树
  • 🍅完全二叉树判断套路版
  • 🍅最大二叉搜索树的头节点
  • 🍅最低公共祖先
  • 🍅派对的最大快乐值

🍅递归套路

介绍二叉树的递归套路
1)假设以X节点为头,假设可以向X左树和X右树要任何信息
2)在上一步的假设下,讨论以X为头节点的树,得到答案的可能性(最重要)
3)列出所有可能性后,确定到底需要向左树和右树要什么样的信息
4)把左树信息和右树信息求全集,就是任何一棵子树都需要返回的信息S
5)递归函数都返回S,每一棵子树都这么要求
6)写代码,在代码中考虑如何把左树的信息和右树信息整合出整棵树的信息

🍅判断二叉树是不是平衡二叉树

题目:
给定一棵二叉树的头节点head,返回这棵二叉树是不是平衡二叉树

题解思路:
对于任一节点X,满足以下三个条件,才能保证这棵二叉树是平衡二叉树。
1)X的左树是平衡二叉树
2)X的右树是平衡二叉树
3)|X的左树高度-右树高度|<2

所以需要定义信息体,包含以节点X为头节点的树是否平,以及它的高度两个信息。

代码实现:

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

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

    public static boolean isBalanced(Node head) {
        return process(head).isBalanced;
    }

    public static class Info {
        public boolean isBalanced;
        public int height;

        public Info(boolean isBalanced, int height) {
            this.isBalanced = isBalanced;
            this.height = height;
        }
    }

    public static Info process(Node x) {
        if(x==null) {
            return new Info(true,0);
        }
        Info leftInfo=process(x.left);
        Info rightInfo=process(x.right);
        int height=Math.max(leftInfo.height, rightInfo.height)+1;
        boolean isBalanced=true;
        if(!leftInfo.isBalanced||!rightInfo.isBalanced) {
            isBalanced=false;
        }
        if(Math.abs(leftInfo.height- rightInfo.height)>1) {
            isBalanced=false;
        }
        return new Info(isBalanced,height);
    }
}

🍅判断二叉树是不是搜索二叉树

题目:
给定头节点,判断是不是搜索二叉树

题解思路:
每一棵子树,左子树的所有值都比头节点的值小,右子树的所有值都比头节点的值大。
(中序遍历是有序的)
信息体需要包含以下信息:
1、是否是二叉搜索树
2、树上的最大值
3、树上的最小值

判断:
以X为头节点的树
1、左子树是否是搜索二叉树
2、右子树是否是搜索二叉树
3、左子树最大值是否小于X.val
4、右子树最小值是否大于X.val

代码实现:

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

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

    public static class Info {
        public boolean isBST;
        public int max;
        public int min;

        public Info(boolean isBST, int max, int min) {
            this.isBST = isBST;
            this.max = max;
            this.min = min;
        }
    }

    public static boolean isBST(Node head) {
        if(head==null) {
            return true;
        }
        return process(head).isBST;
    }
    
    public static Info process(Node x) {
        if(x==null) return null;
        Info leftInfo=process(x.left);
        Info rightInfo=process(x.right);
        int max=x.value;
        if (leftInfo != null) {
            max = Math.max(max, leftInfo.max);
        }
        if (rightInfo != null) {
            max = Math.max(max, rightInfo.max);
        }
        int min = x.value;
        if (leftInfo != null) {
            min = Math.min(min, leftInfo.min);
        }
        if (rightInfo != null) {
            min = Math.min(min, rightInfo.min);
        }
        boolean isBST=true;
        if(leftInfo!=null&& !leftInfo.isBST) {
            isBST=false;
        }
        if(rightInfo!=null&&!rightInfo.isBST) {
            isBST=false;
        }
        if(leftInfo!=null&&leftInfo.max>=x.value) {
            isBST=false;
        }
        if(rightInfo!=null&& rightInfo.min<=x.value) {
            isBST=false;
        }
        return new Info(isBST,max,min);
    }
}

🍅二叉树最大直径

题目:
给定一棵二叉树的头节点head,任何两个节点之间都存在距离,返回整棵二叉树的最大距离

题解思路:
对于任一节点X,以X为头节点的二叉树的最大距离有以下三种可能:
1、X左树的最大距离(不经过X)
2、X右树的最大距离(不经过X)
3、X左树与X最远的距离+X右树与X最远的距离+1(左树或右树与X的最大距离就是树的高度)

所以信息体需要包含以下内容:
1、最大距离
2、树的高度

代码实现:

import java.util.ArrayList;

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

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

    public static class Info {
        public int maxDistance;
        public int height;

        public Info(int maxDistance, int height) {
            this.maxDistance = maxDistance;
            this.height = height;
        }
    }
    
    public static int maxDistance(Node head) {
        return process(head).maxDistance;
    }
    public static Info process(Node x) {
        if(x==null) {
            return new Info(0,0);
        }
        Info leftInfo=process(x.left);
        Info rightInfo=process(x.right);
        int height=Math.max(leftInfo.height, rightInfo.height)+1;
        int p1=leftInfo.maxDistance;
        int p2=rightInfo.maxDistance;
        int p3= leftInfo.height+ rightInfo.height+1;
        int maxDistance=Math.max(Math.max(p1,p2),p3);
        return new Info(maxDistance,height);
    }
}

🍅判断二叉树是不是满二叉树

题目:
给定一棵二叉树的头节点head,判断这棵二叉树是不是满二叉树

题解思路:
满二叉树的高度为h,则节点数为2^h-1.
所以定义的信息体包含两个信息(高度和节点数)
返回头节点的信息体就能判断该二叉树是不是满二叉树。

代码实现:

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

        public Node(int value) {
            this.value = value;
        }
    }
    
    public static class Info {
        public int height;
        public int nodes;

        public Info(int height, int nodes) {
            this.height = height;
            this.nodes = nodes;
        }
    }
    
    public static boolean isFull(Node head) {
        if(head==null) {
            return true;
        }
        Info all=process(head);
        return (1<< all.height)-1== all.nodes;
    }
    
    public static Info process(Node head) {
        if(head==null) {
            return new Info(0,0);
        }
        Info leftInfo=process(head.left);
        Info rightInfo=process(head.right);
        int height=Math.max(leftInfo.height, rightInfo.height)+1;
        int nodes= leftInfo.nodes+ rightInfo.nodes;
        return new Info(height,nodes);
    }
}

🍅最大二叉搜索树

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

题解思路:
求最大二叉搜索树,当X节点不做头时,有两种可能:
1、X左子树的最大二叉搜索树大小
2、X右子树的最大二叉搜索树大小
当X节点做头时,需要知道以下三个信息:
1、X左树是否是BST X右树是否是BST
2、X左树的max是否小于X.val X右树的min是否大于X.val
3、X左树的size +X右树的size+1

得到信息体即包含以下信息:
1、最大二叉搜索子树大小
2、树上max
3、树上min
4、整棵树的size
5、是否是BST(该条件可以省略,如果1 == 4即可得到5)

代码实现:

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

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

    public static class Info {
        public int maxSubBSTHead;
        public int size;
        public int max;
        public int min;

        public Info(int maxSubBSTHead, int size, int max, int min) {
            this.maxSubBSTHead = maxSubBSTHead;
            this.size = size;
            this.max = max;
            this.min = min;
        }
    }

    public 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 size=1;
        if(leftInfo!=null) {
            max=Math.max(max, leftInfo.max);
            min=Math.min(min, leftInfo.min);
            size+= leftInfo.size;
        }
        if(rightInfo!=null) {
            max=Math.max(max, rightInfo.max);
            min=Math.min(min, rightInfo.min);
            size+= rightInfo.size;
        }
        int p1=-1;
        if(leftInfo!=null) {
            p1=leftInfo.maxSubBSTHead;
        }
        int p2=-1;
        if(rightInfo!=null) {
            p2=rightInfo.maxSubBSTHead;
        }
        int p3=-1;
        boolean leftBST=leftInfo==null?true:(leftInfo.maxSubBSTHead== leftInfo.size);
        boolean rightBST=rightInfo==null?true:(rightInfo.maxSubBSTHead== rightInfo.size);
        if(leftBST&&rightBST) {
            boolean leftMaxLessX=leftInfo==null?true:(leftInfo.max<x.value);
            boolean rightMinMoreX=rightInfo==null?true:(x.value< rightInfo.min);
            if(leftMaxLessX&&rightMinMoreX) {
                p3=size;
            }
        }
        return new Info(Math.max(p1,Math.max(p2,p3)),size,max,min);
    }
}

🍅完全二叉树判断套路版

题目:
判断二叉树是不是完全二叉树(一般方法解决、递归套路解决)
题解思路:
对于以节点X为头节点的二叉树,有以下四种可能,可以使得该二叉树为完全二叉树。
1)左树满,右树满,左树高度 == 右树高度
2)左树是完全二叉树,右树满,左树高度 == 右树高度+1
3)左树满,右树满,左高 == 右高+1
4)左树满。右树是完全二叉树,左高 == 右高

所以定义信息体,需要包含以下信息:
1、是否满
2、是否是完全二叉树
3、高度
代码实现:

public class IsCBT {
    public static class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

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

    public static class Info {
        public boolean isFull;
        public boolean isCBT;
        public int height;

        public Info(boolean isFull, boolean isCBT, int height) {
            this.isFull = isFull;
            this.isCBT = isCBT;
            this.height = height;
        }
    }
    
    public static Info process(TreeNode x) {
        if(x==null) {
            return new Info(true,true,0);
        }
        Info leftInfo=process(x.left);
        Info rightInfo=process(x.right);
        int height=Math.max(leftInfo.height,rightInfo.height)+1;
        boolean isFull= leftInfo.isFull&& rightInfo.isFull&&leftInfo.height== rightInfo.height;
        boolean isCBT=false;
        if(leftInfo.isFull&& rightInfo.isFull&&leftInfo.height== rightInfo.height) {
            isCBT=true;
        }else if(leftInfo.isCBT&& rightInfo.isFull&&leftInfo.height== rightInfo.height+1) {
            isCBT=true;
        }else if (leftInfo.isFull&& rightInfo.isFull&&leftInfo.height== rightInfo.height+1) {
            isCBT=true;
        }else if(leftInfo.isFull&&rightInfo.isCBT&&leftInfo.height== rightInfo.height) {
            isCBT=true;
        }
        return new Info(isFull,isCBT,height);
    }
}

🍅最大二叉搜索树的头节点

给定一棵二叉树的头节点head,返回这颗二叉树中最大的二叉搜索子树的头节点
题解思路:
求最大二叉搜索树的头节点,对于任一节点X来说,有以下两种情况。
1、与X无关(即X不是最大二叉搜索树的头节点)
1)X左树的最大二叉搜索树的头节点
2)X右树的最大二叉搜索树的头节点

2、与X有关(即X为最大二叉搜索树的头节点),那么需要以下条件
1)左树、右树为二叉搜索树
2)左树最大值<X.val 右树最小值>X.val
3)该树的大小

所以信息体需包含以下信息:
1)最大二叉搜索树的头节点
2)最大二叉搜索树的节点个数
3)max
4)min

代码实现:

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

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

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

        public Info(Node maxSubBSTHead, int maxSubBSTSize, int max, int min) {
            this.maxSubBSTHead = maxSubBSTHead;
            this.maxSubBSTSize = maxSubBSTSize;
            this.max = max;
            this.min = min;
        }
    }

    public 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;
        Node maxSubBSTHead=null;
        int maxSubBSTSize=0;
        if(leftInfo!=null) {
            max=Math.max(max, leftInfo.max);
            min=Math.min(min, leftInfo.min);
            maxSubBSTHead=leftInfo.maxSubBSTHead;
            maxSubBSTSize= leftInfo.maxSubBSTSize;
        }
        if(rightInfo!=null) {
            max=Math.max(max, rightInfo.max);
            min=Math.min(min, rightInfo.min);
            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,max,min);
    }
}

🍅最低公共祖先

题目:
给定一棵二叉树的头节点head,和另外两个节点a和b,返回a和b的最低公共祖先
题解思路:
对于任一节点X,就找X是否是a、b最低公共祖先即可。
1)与X无关(X不是最低汇聚点)
1.左树有答案
2.右树有答案
3.a、b不都在X为头节点的子树上

2)X是答案
1.左右子树a、b各一个
2.X是a,b在左子树或者右子树
3.X是b,a在左子树或者右子树

信息体包含:
1.a是否在树上
2.b是否在树上
3.最低公共祖先节点

代码实现:

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

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

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

    public static class Info {
        public boolean findA;
        public boolean findB;
        public Node ans;

        public Info(boolean findA, boolean findB, Node ans) {
            this.findA = findA;
            this.findB = findB;
            this.ans = ans;
        }
    }

    public 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);
    }
}

🍅派对的最大快乐值

题目:
员工信息的定义如下:
class Employee {
public int happy; // 这名员工可以带来的快乐值
List subordinates; // 这名员工有哪些直接下级
}
公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树
树的头节点是公司唯一的老板,除老板之外的每个员工都有唯一的直接上级
叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外每个员工都有一个或多个直接下级
这个公司现在要办party,你可以决定哪些员工来,哪些员工不来,规则:
1.如果某个员工来了,那么这个员工的所有直接下级都不能来
2.派对的整体快乐值是所有到场员工快乐值的累加
3.你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss,请返回派对的最大快乐值。
题解思路:
对于任一节点X,若想求最大快乐值,有以下两种情况:
1、X来,则X.happy+所有直系子节点不来的maxHappy
2、X不来,则0+所有直系字节的来与不来两种情况下获得的maxHappy

则得到信息体包含以下信息:
X来的情况下的maxHappy
X不来的情况下的maxHappy

代码实现:

public class MaxHappy {
    public static class Employee {
        public int happy;
        public List<Employee> nexts;

        public Employee(int happy) {
            this.happy = happy;
            this.nexts = new ArrayList<>();
        }
    }

    public static int maxHappy(Employee boss) {
        Info allInfo=process(boss);
        return Math.max(allInfo.no, allInfo.yes);
    }

    public static class Info {
        public int no;
        public int yes;

        public Info(int no, int yes) {
            this.no = no;
            this.yes = yes;
        }
    }
    
    public static Info process(Employee x) {
        if(x==null) {
            return new Info(0,0);
        }
        int no=0;
        int yes=x.happy;
        for (Employee next:x.nexts) {
            Info nextInfo=process(next);
            no+=Math.max(nextInfo.no, nextInfo.yes);
            yes+=nextInfo.no;
        }
        return new Info(no,yes);
    }
}

⭐️最后的话⭐️
总结不易,希望uu们不要吝啬你们的👍哟(^U^)ノ~YO!!如有问题,欢迎评论区批评指正😁

请添加图片描述


http://www.niftyadmin.cn/n/360478.html

相关文章

Java设计模式-迭代器模式

简介 在软件开发中&#xff0c;设计模式是经验丰富的开发者们总结出的可复用的解决方案&#xff0c;它们可以帮助我们解决常见的设计问题。在Java领域中&#xff0c;迭代器模式是一种常用的设计模式&#xff0c;它提供了一种优雅的方式来遍历集合对象&#xff0c;同时与其他设…

docker随笔

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、namespace&#xff1f;二、CGroups可以做资源配额三、docker run --link是什么意思总结 一、namespace&#xff1f; docker的资源隔离有3种namespace 二、CGr…

从索引结点出发探索软、硬链接

索引结点的初步认识 对于整个计算机系统的资源管理&#xff0c;我们可以认为&#xff0c;OS先将这些资源的数据信息&#xff0c;给描述起来构成一个部分&#xff0c;然后再将它们组织起来&#xff0c;就能够实现由OS集中管理。举一个最经典的例子&#xff0c;进程的引入是为了…

架构设计之复用性概谈

作为开发人员&#xff0c;你对复用这个概念一定不陌生。在开发过程中&#xff0c;我们把系统中通用的代码逻辑抽取出来&#xff0c;变成公共方法或公共类&#xff0c;然后在多个地方调用&#xff0c;这就是最简单的技术上的复用。 但一开始&#xff0c;我们不会过多地考虑复用&…

【Python Power BI】零基础也能轻松掌握的学习路线与参考资料

Python和Power BI是现代数据分析和可视化领域中最受欢迎的工具之一&#xff0c;Python是一种高级编程语言&#xff0c;广泛用于数据科学和分析&#xff0c;而Power BI是一种业务智能工具&#xff0c;用于创建交互式大屏幕和实时报表。Python和Power BI的结合使用可以为数据科学…

简单算法部署

1部署工具/技术介绍 1.1、ONNX 现在很多的深度学习框架提供的功能都是类似的&#xff0c;但是在 API、计算图和 runtime 方面却是独立的&#xff0c;这就给 AI 开发者在不同平台部署不同模型带来了很多困难和挑战&#xff0c;ONNX 的目的在于提供一个跨框架的模型中间表达框架…

如何搭建远程服务器-(cpolar)

文章目录 前言一、安装注册下载安装包认证开通指定端口监听开机自启动设置 二、使用步骤电脑端远程手机端远程 三、卸载软件安装说明&#xff1a; 总结 前言 之前已经有写到一篇文章《如何用树莓派搭建远程服务器 (zerotier)》&#xff0c;对此已经使用了很长一段时间。 优点…

利用无代码工具开发一款小程序

目录 无代码工具开发小程序的流程需求分析阶段模型设计阶段页面搭建阶段创建项目创建数据表组件搭建 预览发布总结 日常我们开发小程序的时候都是要从写代码开始&#xff0c;但是写代码这个事只有专业开发才可以干&#xff0c;那作为普通人&#xff0c;如果也希望开发小程序&am…