最大搜索子树

举报
兔老大 发表于 2021/04/23 02:19:01 2021/04/23
【摘要】 给定一个二叉树的头结点,返回最大搜索子树的大小。   我们先定义结点: public static class Node { public int value; public Node left; public Node right; public Node(int data) { this.value = data; } } 分析: 直...

给定一个二叉树的头结点,返回最大搜索子树的大小。

 

我们先定义结点:


  
  1. public static class Node {
  2. public int value;
  3. public Node left;
  4. public Node right;
  5. public Node(int data) {
  6. this.value = data;
  7. }
  8. }

分析:

直接判断每个节点左边小右边大是不对滴

 

可以暴力判断所有的子树,就不说了。

 

最大搜索子树可能性:

第一种可能性,以node为头的结点的最大二叉搜索子树可能来自它左子树;
第二种可能性,以node为头的结点的最大二叉搜索子树可能来自它右子树;
第三种可能性,左树整体是搜索二叉树,右树整体也是搜索二叉树,而且左树的头是node.left,右树的头是node.right,且左树的最大值< node.value,右树的最小值 > node.value, 那么以我为头的整棵树都是搜索二叉树;
 

第三种可能性的判断,需要的信息有:左子树的最大值、右子树的最小值、左子树是不是搜索二叉树、右子树是不是搜索二叉树

还有左右搜索二叉树的最大深度。

我们判断了自己,并不知道自己是哪边的子树,我们要返回自己的最大值和最小值。

这样,定义一个返回类型:


  
  1. public static class ReturnType{
  2. public int size;//最大搜索子树深度
  3. public Node head;//最大搜索子树的根
  4. public int min;//子树最小
  5. public int max;//子树最大
  6. public ReturnType(int a, Node b,int c,int d) {
  7. this.size =a;
  8. this.head = b;
  9. this.min = c;
  10. this.max = d;
  11. }
  12. }

然后开始写代码:

注意:

1)NULL返回深度0,头为NULL,最大值最小值返回系统最大和最小,这样才不会影响别的判断。


  
  1. public static ReturnType process(Node head) {
  2. if(head == null) {
  3. return new ReturnType(0,null,Integer.MAX_VALUE, Integer.MIN_VALUE);
  4. }
  5. Node left = head.left;//取信息
  6. ReturnType leftSubTressInfo = process(left);
  7. Node right = head.right;
  8. ReturnType rightSubTressInfo = process(right);
  9. int includeItSelf = 0;
  10. if(leftSubTressInfo.head == left // 左子树为搜索树
  11. &&rightSubTressInfo.head == right// 右子树为搜索树
  12. && head.value > leftSubTressInfo.max// 左子树最大值小于当前节点
  13. && head.value < rightSubTressInfo.min//右子树最小值大于当前节点
  14. ) {
  15. includeItSelf = leftSubTressInfo.size + 1 + rightSubTressInfo.size;//当前节点为根的二叉树为搜索树
  16. }
  17. int p1 = leftSubTressInfo.size;
  18. int p2 = rightSubTressInfo.size;
  19. int maxSize = Math.max(Math.max(p1, p2), includeItSelf);//最大搜索树深度
  20. Node maxHead = p1 > p2 ? leftSubTressInfo.head : rightSubTressInfo.head;
  21. if(maxSize == includeItSelf) {
  22. maxHead = head;
  23. }//最大搜索树的根:来自左子树、来自右子树、本身
  24. return new ReturnType(
  25. maxSize, //深度
  26. maxHead, //根
  27. Math.min(Math.min(leftSubTressInfo.min,rightSubTressInfo.min),head.value), //最小
  28. Math.max(Math.max(leftSubTressInfo.max,rightSubTressInfo.max),head.value)); //最大
  29. }

可以进一步改进:

空间浪费比较严重

其实返回值为三个int,一个node,我们可以把三个int合起来,用全局数组记录,函数只返回node(搜索树的根)即可。

给出完整代码:


  
  1. public class BiggestSubBSTInTree {
  2. public static class Node {
  3. public int value;
  4. public Node left;
  5. public Node right;
  6. public Node(int data) {
  7. this.value = data;
  8. }
  9. }
  10. public static Node biggestSubBST(Node head) {
  11. int[] record = new int[3]; // 0->size, 1->min, 2->max
  12. return posOrder(head, record);
  13. }
  14. public static class ReturnType{
  15. public int size;//最大搜索子树深度
  16. public Node head;//最大搜索子树的根
  17. public int min;//子树最小
  18. public int max;//子树最大
  19. public ReturnType(int a, Node b,int c,int d) {
  20. this.size =a;
  21. this.head = b;
  22. this.min = c;
  23. this.max = d;
  24. }
  25. }
  26. public static ReturnType process(Node head) {
  27. if(head == null) {
  28. return new ReturnType(0,null,Integer.MAX_VALUE, Integer.MIN_VALUE);
  29. }
  30. Node left = head.left;//取信息
  31. ReturnType leftSubTressInfo = process(left);
  32. Node right = head.right;
  33. ReturnType rightSubTressInfo = process(right);
  34. int includeItSelf = 0;
  35. if(leftSubTressInfo.head == left // 左子树为搜索树
  36. &&rightSubTressInfo.head == right// 右子树为搜索树
  37. && head.value > leftSubTressInfo.max// 左子树最大值小于当前节点
  38. && head.value < rightSubTressInfo.min//右子树最小值大于当前节点
  39. ) {
  40. includeItSelf = leftSubTressInfo.size + 1 + rightSubTressInfo.size;//当前节点为根的二叉树为搜索树
  41. }
  42. int p1 = leftSubTressInfo.size;
  43. int p2 = rightSubTressInfo.size;
  44. int maxSize = Math.max(Math.max(p1, p2), includeItSelf);//最大搜索树深度
  45. Node maxHead = p1 > p2 ? leftSubTressInfo.head : rightSubTressInfo.head;
  46. if(maxSize == includeItSelf) {
  47. maxHead = head;
  48. }//最大搜索树的根:来自左子树、来自右子树、本身
  49. return new ReturnType(
  50. maxSize, //深度
  51. maxHead, //根
  52. Math.min(Math.min(leftSubTressInfo.min,rightSubTressInfo.min),head.value), //最小
  53. Math.max(Math.max(leftSubTressInfo.max,rightSubTressInfo.max),head.value)); //最大
  54. }
  55. public static Node posOrder(Node head, int[] record) {
  56. if (head == null) {
  57. record[0] = 0;
  58. record[1] = Integer.MAX_VALUE;
  59. record[2] = Integer.MIN_VALUE;
  60. return null;
  61. }
  62. int value = head.value;
  63. Node left = head.left;
  64. Node right = head.right;
  65. Node lBST = posOrder(left, record);
  66. int lSize = record[0];
  67. int lMin = record[1];
  68. int lMax = record[2];
  69. Node rBST = posOrder(right, record);
  70. int rSize = record[0];
  71. int rMin = record[1];
  72. int rMax = record[2];
  73. record[1] = Math.min(rMin, Math.min(lMin, value)); // lmin, value, rmin -> min
  74. record[2] = Math.max(lMax, Math.max(rMax, value)); // lmax, value, rmax -> max
  75. if (left == lBST && right == rBST && lMax < value && value < rMin) {
  76. record[0] = lSize + rSize + 1;//修改深度
  77. return head; //返回根
  78. }//满足当前构成搜索树的条件
  79. record[0] = Math.max(lSize, rSize);//较大深度
  80. return lSize > rSize ? lBST : rBST;//返回较大搜索树的根
  81. }
  82. // for test -- print tree
  83. public static void printTree(Node head) {
  84. System.out.println("Binary Tree:");
  85. printInOrder(head, 0, "H", 17);
  86. System.out.println();
  87. }
  88. public static void printInOrder(Node head, int height, String to, int len) {
  89. if (head == null) {
  90. return;
  91. }
  92. printInOrder(head.right, height + 1, "v", len);
  93. String val = to + head.value + to;
  94. int lenM = val.length();
  95. int lenL = (len - lenM) / 2;
  96. int lenR = len - lenM - lenL;
  97. val = getSpace(lenL) + val + getSpace(lenR);
  98. System.out.println(getSpace(height * len) + val);
  99. printInOrder(head.left, height + 1, "^", len);
  100. }
  101. public static String getSpace(int num) {
  102. String space = " ";
  103. StringBuffer buf = new StringBuffer("");
  104. for (int i = 0; i < num; i++) {
  105. buf.append(space);
  106. }
  107. return buf.toString();
  108. }
  109. public static void main(String[] args) {
  110. Node head = new Node(6);
  111. head.left = new Node(1);
  112. head.left.left = new Node(0);
  113. head.left.right = new Node(3);
  114. head.right = new Node(12);
  115. head.right.left = new Node(10);
  116. head.right.left.left = new Node(4);
  117. head.right.left.left.left = new Node(2);
  118. head.right.left.left.right = new Node(5);
  119. head.right.left.right = new Node(14);
  120. head.right.left.right.left = new Node(11);
  121. head.right.left.right.right = new Node(15);
  122. head.right.right = new Node(13);
  123. head.right.right.left = new Node(20);
  124. head.right.right.right = new Node(16);
  125. printTree(head);
  126. Node bst = biggestSubBST(head);
  127. printTree(bst);
  128. }
  129. }

 

文章来源: fantianzuo.blog.csdn.net,作者:兔老大RabbitMQ,版权归原作者所有,如需转载,请联系作者。

原文链接:fantianzuo.blog.csdn.net/article/details/84251431

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。