树的递归思想套路使用
* 二叉树的递归套路总结(递归的最核心思想:通过递归,可以把任何问题都简化为根节点,左儿子,右儿子的问题
* 即:把左右子树通过递归给归一化为左右儿子节点(把整棵树看作一个整体))
* 1.进行递归,分别从根节点向左子树和右子树进行递归(对任何问题通用)
* 2.分析题目所要求的条件,去根据题目要求得到根节点,左子树和右子树的逻辑关系,并在每一次递归中将这种
* 关系给模拟出来(因为使用了递归,其实就可以把一整棵子树看作一个节点来进行考虑)
*
* 补充:因为我们通常是把一棵子树抽象成一个节点来进行考虑,一般来说这个节点要存储多个所需要的值,所以一般
* 都要自己去定义一个返回类型,让所有需要的值都能在递归中返回传递
* 适用条件:对于那些值能够通过递归正常传递的题目类型,可使用该套路。不可使用的例子:求一棵树的中位数
* 得到左子树和右子树的中位数是无法得到新树的中位数,所以无法用该方法求解
举例分析:
例子1:
平衡二叉树:任意节点的左子树和右子树的高度差小于等于1
判断一棵树是否为平衡二叉树
* 套路解析:
* 1.确认递归的方式:从某个节点递归到它的左儿子节点和右儿子节点
* 2.对每个节点的分析(要拆分递归):即该节点的左子树和右子树的高度差小于等于1
代码:
1 public static class ReturnType{//定义一个特殊的返回类型,能同时返回这棵树的最大高度和是否平衡 2 public int height; 3 public boolean isBalance; 4 5 public ReturnType(int height,boolean isBalance) { 6 this.height = height; 7 this.isBalance = isBalance; 8 } 9 } 10 11 //执行递归过程 12 public static ReturnType process(Node root) { 13 if (root == null) { 14 return new ReturnType(0,true); 15 } 16 //对左右子树进行递归 17 ReturnType lt = process(root.left); 18 ReturnType rt = process(root.right); 19 //对每一次递归进行具体的判断分析 20 int height = Math.max(lt.height, rt.height) + 1; 21 //只有当左子树平衡,右子树平衡,且两树高度差小于1时,这棵树才平衡 22 boolean isBalance = lt.isBalance && rt.isBalance && (Math.abs(rt.height - lt.height) <= 1); 23 return new ReturnType(height,isBalance); 24 } 25 //原函数 26 public static boolean isBalanceTree(Node root) { 27 return process(root).isBalance; 28 }
例子2:
判断一棵树是否为搜索二叉树:
1.递归判断左树和右树是否为搜索二叉树
2.判断根节点是否大于左树的最大值(这个最大值因为有了递归,所以不用遍历整棵树,只要在每次递归时都把这个值保存住,一直递归传递即可),是否小于右树的最小值
1 public static class DataType{ 2 public boolean isBST; 3 public int max;//用于左树求最大值 4 public int min;//用于右树求最小值 5 6 public DataType(boolean isBST,int max,int min) { 7 this.isBST = isBST; 8 this.max = max; 9 this.min = min; 10 } 11 } 12 13 public static DataType process1(Node root) { 14 if (root == null) { 15 return null; 16 } 17 //分别获得左右树的信息 18 DataType ld = process1(root.left); 19 DataType rd = process1(root.right); 20 21 //进行比较分析处理 22 int min = root.val, max = root.val; 23 boolean isBST = true; 24 //通过以下操作就可以得到整棵树的最小值和最大值(必须要得到,因为这棵树也可能是子树,用于下一步的递归返回) 25 if (ld != null) { 26 min = Math.min(min, ld.min); 27 max = Math.max(max, ld.max); 28 } 29 if (rd != null) { 30 min = Math.min(min, rd.min); 31 max = Math.max(max, rd.max); 32 } 33 //判断是否为搜索二叉树 34 if (ld != null && (ld.isBST == false || ld.max > root.val)) {//若左树不为空,且不是搜索二叉树 35 //或左树最大值大于根节点的值 36 isBST = false; 37 } 38 if (rd != null && (rd.isBST == false || rd.min < root.val)) {//若右树不为空,且不是搜索二叉树 39 //或右树最小值小于根节点的值 40 isBST = false; 41 } 42 return new DataType(isBST,max,min); 43 }
例子3:判断一棵树是否为满二叉树:
* 1.向左右子树递归
* 2.每次收集子树的高度和节点总数,判断高度和节点的总数关系只要在最后总子树即可
代码及解析:
1 //返回类型:树所在的高度和这棵子树的节点个数 2 public static class Info{ 3 public int height; 4 public int nodes; 5 6 public Info(int height,int nodes) { 7 this.height = height; 8 this.nodes = nodes; 9 } 10 } 11 12 public static Info process2(Node root) { 13 if (root == null) { 14 return new Info(0,0); 15 } 16 Info info1 = process2(root.left); 17 Info info2 = process2(root.right); 18 int height = Math.max(info1.height, info2.height) + 1; 19 int nodes = info1.nodes + info2.nodes + 1; 20 return new Info(height,nodes); 21 } 22 23 public static boolean isFull(Node root) { 24 if (root == null) { 25 return true; 26 } 27 int height = process2(root).height; 28 int nodes = process2(root).nodes; 29 if (Math.pow(2, height) - 1 == nodes) { 30 return true; 31 } 32 else { 33 return false; 34 } 35 }