【算法自由之路】二叉树的递归套路
创始人
2024-05-22 03:20:36
0

【算法自由之路】二叉树的递归套路

预热,二叉树的后继节点

话不多说,首先是一道练手题,寻找二叉树任意给定节点的后继节点,此二叉树具备一个指向父节点的指针。

后继节点:在中序遍历中于给定节点后一个打印的节点

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

这道题其实主要考验的是分类讨论和找规律的能力。首先理解中序遍历对每个子树打印顺序都是 左 中 右。比如下图这个树

做分类讨论其实就两个情况:

  1. 该节点有右节点:后继为右节点的最左节点
  2. 该节点没有右节点:后继节点为向上找,第一次子节点是父节点的左孩子的父节点,比如 8 的后继就是 4

对于情况 2 我们其实可以反推来理解, 4 节点的前驱节点应该是 左子树的最右的一个节点。

在这里插入图片描述

package algorithmic.base.tree;/*** @program: algorithmic-total-solution* @description: 查找二叉树的后继节点,* @author: wangzibin* @create: 2023-01-10**/
public class FindNextNode {public static class TreeNode {public int val;public TreeNode left;public TreeNode right;public TreeNode parent;public TreeNode(int val) {this.val = val;}@Overridepublic String toString() {return "TreeNode{" +"val=" + val +'}';}}public static void print(TreeNode node) {if (node == null) {return;}print(node.left);System.out.print(node.val);print(node.right);}public static TreeNode findNextNode(TreeNode node) {if (node == null) {return null;}TreeNode result = null;// 如果有右孩子,后继节点是右孩子的最左节点if (node.right != null) {result = node.right;while (result.left != null) {result = result.left;}return result;}// 如果没有右孩子,向上找第一个子孩子是左节点的父节点 (有点绕,看代码)result = node.parent;// 注意最右节点没有后继节点while (node.parent != null && node != result.left) {node = node.parent;result = node.parent;}return result;}public static void main(String[] args) {TreeNode head = new TreeNode(2);TreeNode node1 = new TreeNode(1);TreeNode node3 = new TreeNode(3);TreeNode node4 = new TreeNode(4);TreeNode node5 = new TreeNode(5);TreeNode node6 = new TreeNode(6);TreeNode node7 = new TreeNode(7);TreeNode node8 = new TreeNode(8);head.left = node1;node1.parent = head;head.right = node3;node3.parent = head;node3.right = node4;node4.parent = node3;node4.left = node5;node5.parent = node4;node4.right = node6;node6.parent = node4;node5.right = node7;node7.parent = node5;node7.right = node8;node8.parent = node7;print(head);System.out.println();System.out.println(findNextNode(node1));System.out.println(findNextNode(head));System.out.println(findNextNode(node3));System.out.println(findNextNode(node5));System.out.println(findNextNode(node7));System.out.println(findNextNode(node8));System.out.println(findNextNode(node4));System.out.println(findNextNode(node6));}}

递归套路

二叉树的递归套路有点像拆分子任务,将要求的最终结果分给每个分支去做

在实际应用中,对于一个整个树的问题,假设可以向左右子树要任何信息,整合信息后得出最终结果

整个拆分任务的操作我们交给了堆栈去做

递归套路 1 判断一个二叉树是平衡二叉树

平衡二叉树定义:对于树中任意一个节点,其左子树和右子树的高度差不超过 1。

这里假设我可以向左右子树获取任何信息,那对于判断我是否是平衡二叉树的关系信息是:

  1. 子树高度
  2. 子树是否是平衡二叉树

于是我可以定义这样一个返回结构

    public static class NodeInfo {public boolean isBalanced;public int high;public NodeInfo(boolean isBalanced, int high) {this.isBalanced = isBalanced;this.high = high;}}

最终代码很简单

public class BalanceTree {public static class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) {this.val = val;}TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}public static class NodeInfo {public boolean isBalanced;public int high;public NodeInfo(boolean isBalanced, int high) {this.isBalanced = isBalanced;this.high = high;}}public boolean isBalanced(TreeNode root) {return getNodeInfo(root).isBalanced;}public NodeInfo getNodeInfo(TreeNode node) {if (node == null) {return new NodeInfo(true, 0);}// 获取左子树信息NodeInfo left = getNodeInfo(node.left);// 获取右子树信息NodeInfo right = getNodeInfo(node.right);// 如果左右子树都平衡且高度差为 1 则我也平衡boolean isBalanced = left.isBalanced && right.isBalanced && Math.abs(left.high - right.high) <= 1;// 我的高度为左右子树最大高度 +1int high = Math.max(left.high, right.high) + 1;return new NodeInfo(isBalanced, high);}}

可以直接到 leetcode 验证 平衡二叉树

感受到二叉树的递归套路的魅力了吗?关键点在于:

  1. 思考 当前 节点 与 左右子节点的关系 (一般的我们可以以 以 与当前节点有关与当前节点无关 来进行分类讨论 )
  2. 向左右子节点获取什么信息能够计算出我的信息
  3. 整合信息,定义结构

递归套路 2 计算给定树结构中二叉搜索子树的最大键和值

首先定义二叉搜索数 : 对于树中任意一个节点,其左树都小于该节点,右树都大于该节点

需要向左右节点要的信息:

  1. 树的最大值
  2. 树的最小值
  3. 是否是二叉搜索树
  4. 当前树的键和值
  5. 二叉搜索子树的最大键和值

在递归中就需要讨论最终结果是否与当前节点有关了,直接看代码

package algorithmic.base.tree;import javax.xml.soap.Node;/*** @program: algorithmic-total-solution* @description: 二叉搜索子树最大键和值  https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree/* @author: wangzibin* @create: 2023-01-11**/
public class MaxSumBST {public static class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) {this.val = val;}TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}}public static class NodeInfo {// 当前节点子树最大值private int max;private int min;private boolean isBst;private int bstSum;private int bstMaxSum;@Overridepublic String toString() {return "NodeInfo{" +"max=" + max +", min=" + min +", isBst=" + isBst +", bstSum=" + bstSum +", bstMaxSum=" + bstMaxSum +'}';}}public static NodeInfo getInfo(TreeNode node) {if (node == null) {NodeInfo empty = new NodeInfo();empty.isBst = true;empty.min = Integer.MAX_VALUE;empty.max = Integer.MIN_VALUE;return empty;}NodeInfo leftInfo = getInfo(node.left);NodeInfo rightInfo = getInfo(node.right);NodeInfo current = new NodeInfo();current.max = max(node.val, leftInfo.max, rightInfo.max);current.min = min(node.val, leftInfo.min, rightInfo.min);// 判断是否与我有关, 当且仅当我也是二叉搜索树时最大值才与我有关,否则只需要比较子树值即可if (leftInfo.isBst && rightInfo.isBst && leftInfo.max < node.val && rightInfo.min > node.val) {// 左右子树都是搜索树,且 左子树最大值 小于 当前节点值 ,右子树最小值 大于 当前节点值,则可讨论与当前节点有关的情况current.isBst = true;current.bstSum = node.val + leftInfo.bstSum + rightInfo.bstSum;current.bstMaxSum = max(current.bstSum, leftInfo.bstMaxSum, rightInfo.bstMaxSum);} else {current.isBst = false;current.bstMaxSum = Math.max(leftInfo.bstMaxSum, rightInfo.bstMaxSum);}return current;}public static int max(int num1, int num2, int num3) {return Math.max(Math.max(num1, num2), num3);}public static int min(int num1, int num2, int num3) {return Math.min(Math.min(num1, num2), num3);}public static int maxSumBST(TreeNode root) {if (root == null) {return 0;}int bstMaxSum = getInfo(root).bstMaxSum;return Math.max(bstMaxSum, 0);}public static void main(String[] args) {TreeNode treeNode1 = new TreeNode(1);treeNode1.left = null;TreeNode treeNode10 = new TreeNode(10);TreeNode treeNode5 = new TreeNode(-5);TreeNode treeNode20 = new TreeNode(20);treeNode1.right = treeNode10;treeNode10.left = treeNode5;treeNode10.right = treeNode20;System.out.println(maxSumBST(treeNode1));}}

验证正确性 1373. 二叉搜索子树的最大键值和

相关内容

热门资讯

安卓系统应用数据目录,揭秘系统... 你有没有想过,你的安卓手机里那些应用,它们的数据都藏在哪个角落呢?今天,就让我带你一探究竟,揭开安卓...
kindle 安卓 系统 刷机... 亲爱的读者们,你是不是也和我一样,对电子阅读设备情有独钟?尤其是那款小巧便携的Kindle,简直是阅...
平板 win 安卓 双系统,... 你有没有想过,拥有一台既能运行Windows系统,又能流畅使用安卓应用的多功能平板电脑,是不是能让你...
电脑安卓和苹果系统,电脑操作系... 你有没有发现,现在无论是工作还是娱乐,电脑已经成了我们生活中不可或缺的好伙伴呢!而在这众多电脑中,安...
手机安卓系统下载5.0,引领智... 你有没有发现,最近手机界又掀起了一股热潮?没错,就是安卓系统5.0的下载。这可是安卓家族里的一大亮点...
小森生活系统安卓,打造绿色生态... 你知道吗?最近在手机应用市场上,有个叫做“小森生活系统安卓”的新玩意儿火得一塌糊涂。它就像一个神奇的...
王者荣耀安卓系统更换,畅享全新... 最近是不是发现你的王者荣耀游戏体验有点不对劲?别急,让我来给你揭秘一下安卓系统更换背后的那些事儿!一...
ios系统数据如何导入安卓系统... 你是不是也有过这样的经历:手机里存满了珍贵的照片、视频和联系人,突然有一天,你决定换一台安卓手机,却...
王者荣耀启动安卓系统,畅享指尖... 你知道吗?最近王者荣耀可是大动作连连,竟然宣布要启动安卓系统了!这消息一出,瞬间在游戏圈引起了不小的...
安卓始终显示系统栏,安卓系统栏... 你是不是也遇到了这个问题?手机屏幕上那个讨厌的系统栏,有时候它就像一个顽皮的小鬼,总是赖在你的屏幕上...
苹果系统可以装在安卓,探索跨平... 你知道吗?最近在科技圈里可是掀起了一股热潮呢!那就是——苹果系统竟然可以装在安卓设备上!是不是听起来...
安卓系统双清目的,安卓系统双清... 你知道吗?最近在安卓系统圈子里,有个话题可是热得不得了,那就是“双清”。别小看这个“双清”,它可是关...
安卓系统台电平板,畅享智能生活... 你有没有发现,最近身边的朋友都开始讨论起一款叫做台电的安卓系统平板电脑呢?这可不是随便说说,这款平板...
三菱安卓系统,智能科技与驾驶体... 亲爱的读者,你是否曾好奇过,那些在我们生活中默默无闻的汽车品牌,它们是如何将科技与驾驶体验完美结合的...
安卓系统为什么好,引领智能生活... 你有没有发现,身边的朋友、同事,甚至家人,几乎人手一台安卓手机?这可不是偶然现象哦!安卓系统,这个来...
安卓如何改键盘系统,Andro... 你是不是也和我一样,对安卓手机的键盘系统有点儿不满意?想要换一个更顺手的键盘,但又不知道怎么操作?别...
怎么升级安卓14系统,解锁安卓... 你有没有发现,你的安卓手机最近是不是有点儿慢吞吞的?别急,别急,升级到安卓14系统,让你的手机焕发新...
安卓手机如何系统内录,轻松生成... 你有没有想过,有时候想要记录下手机里的精彩瞬间,却发现没有合适的工具?别急,今天就来教你怎么在安卓手...
最绚丽的安卓系统,最绚丽版本全... 哇,你知道吗?在安卓的世界里,有一款系统,它就像是一颗璀璨的明珠,闪耀着最绚丽的色彩。它就是——最绚...
小米系统安卓通知权限,深度解析... 亲爱的手机控们,你是否曾为手机通知栏里乱糟糟的信息而烦恼?又或者,你是否好奇过,为什么有些应用总是能...