• 递归
  • 技巧的写法
  • 完整测试代码

题目

image.png

递归

解析:
这种题目的解题过程分为三步:

  • 列出所有可能性
  • 列出结点需要的信息,并整合信息(成一个结构体)
  • 改递归 ,先假设左和右都给我信息(黑盒),然后怎么利用左边和右边的信息组出来我该返回的信息,最后basecase(边界)填什么

具体到这个题目:
第一步,列出所有可能性:

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

第二步,列出结点需要的信息:

  • 信息一: 左树最大搜索二叉树大小;
  • 信息二: 右树最大搜索二叉树大小;
  • 信息三: 左树上最大搜索二叉树的头部是什么;
  • 信息四: 右树上最大搜索二叉树的头部是什么;
  • 信息五: 左树上的最大值;
  • 信息六: 右树上的最小值;

整合成一个Pair结构: 信息一和信息二整合:size ,信息三和信息四整合 : head(结点类型),以及信息五和信息六 ;

  1. //返回的类型
  2. static class Pair {
  3. public int size; //左右子树的大小
  4. public Node root; //左右子树的头
  5. public int min;
  6. public int max;
  7. }

然后第三部就是改成递归,具体如下(是后序遍历的顺序(需要左右的信息来构造头部的信息)):

  1. static class Node {
  2. public int value;
  3. public Node left;
  4. public Node right;
  5. public Node(int value) {
  6. this.value = value;
  7. }
  8. }
  9. //返回的类型
  10. static class Pair {
  11. public int size; //左右子树的大小
  12. public Node root; //左右子树的头
  13. public int min;
  14. public int max;
  15. public Pair(int size, Node root, int min, int max) {
  16. this.size = size;
  17. this.root = root;
  18. this.min = min;
  19. this.max = max;
  20. }
  21. }
  22. static Node biggestSubBST(Node head) {
  23. return rec(head).root;
  24. }
  25. static Pair rec(Node head) {
  26. if (head == null)
  27. return new Pair(0, null, Integer.MAX_VALUE, Integer.MIN_VALUE);
  28. Pair L = rec(head.left);
  29. Pair R = rec(head.right);
  30. int msize =
  31. (L.root == head.left && R.root == head.right && L.max < head.value && R.min > head.value)
  32. ? L.size + R.size + 1 : 0;
  33. int maxSize = Math.max(Math.max(L.size, R.size), msize);
  34. Node mroot = L.size > R.size ? L.root : R.root;
  35. if (maxSize == msize) mroot = head;
  36. return new Pair(maxSize, mroot, Math.min(head.value, Math.min(L.min, R.min)),
  37. Math.max(head.value, Math.max(L.max, R.max)));
  38. }

改造的写法

技巧的写法(使用一个数组来记录size,min,max):

  1. static Node biggestSubBST2(Node head) {
  2. int[] rec = new int[3]; //0 记录size 1记录min 2记录max
  3. return rec2(head, rec);
  4. }
  5. static Node rec2(Node head, int[] rec) {
  6. if (head == null) {
  7. rec[0] = 0;
  8. rec[1] = Integer.MAX_VALUE;
  9. rec[2] = Integer.MIN_VALUE;
  10. return null;
  11. }
  12. Node L = rec2(head.left, rec);
  13. int lsize = rec[0], lmin = rec[1], lmax = rec[2];
  14. Node R = rec2(head.right, rec);
  15. int rsize = rec[0], rmin = rec[1], rmax = rec[2];
  16. int msize = (L == head.left && R == head.right && lmax < head.value && rmin > head.value) ? lsize + rsize + 1 : 0;
  17. int maxSize = Math.max(msize, Math.max(lsize, rsize));
  18. Node root = lsize > rsize ? L : R;
  19. if (msize == maxSize) root = head;
  20. rec[0] = maxSize;
  21. rec[1] = Math.min(head.value, Math.min(lmin, rmin));
  22. rec[2] = Math.max(head.value, Math.max(lmax, rmax));
  23. return root;
  24. }

完整测试代码(测试样例)

  1. /**
  2. * 返回一棵树中最大的二叉搜索子树的大小
  3. */
  4. public class BiggestSubBST {
  5. static class Node {
  6. public int value;
  7. public Node left;
  8. public Node right;
  9. public Node(int value) {
  10. this.value = value;
  11. }
  12. }
  13. //返回的类型
  14. static class Pair {
  15. public int size; //左右子树的大小
  16. public Node root; //左右子树的头
  17. public int min;
  18. public int max;
  19. public Pair(int size, Node root, int min, int max) {
  20. this.size = size;
  21. this.root = root;
  22. this.min = min;
  23. this.max = max;
  24. }
  25. }
  26. static Node biggestSubBST(Node head) {
  27. return rec(head).root;
  28. }
  29. static Pair rec(Node head) {
  30. if (head == null)
  31. return new Pair(0, null, Integer.MAX_VALUE, Integer.MIN_VALUE);
  32. Pair L = rec(head.left);
  33. Pair R = rec(head.right);
  34. int msize =
  35. (L.root == head.left && R.root == head.right && L.max < head.value && R.min > head.value)
  36. ? L.size + R.size + 1 : 0;
  37. int maxSize = Math.max(Math.max(L.size, R.size), msize);
  38. Node mroot = L.size > R.size ? L.root : R.root;
  39. if (maxSize == msize) mroot = head;
  40. return new Pair(maxSize, mroot, Math.min(head.value, Math.min(L.min, R.min)),
  41. Math.max(head.value, Math.max(L.max, R.max)));
  42. }
  43. static Node biggestSubBST2(Node head) {
  44. int[] rec = new int[3]; //0 记录size 1记录min 2记录max
  45. return rec2(head, rec);
  46. }
  47. static Node rec2(Node head, int[] rec) {
  48. if (head == null) {
  49. rec[0] = 0;
  50. rec[1] = Integer.MAX_VALUE;
  51. rec[2] = Integer.MIN_VALUE;
  52. return null;
  53. }
  54. Node L = rec2(head.left, rec);
  55. int lsize = rec[0], lmin = rec[1], lmax = rec[2];
  56. Node R = rec2(head.right, rec);
  57. int rsize = rec[0], rmin = rec[1], rmax = rec[2];
  58. int msize = (L == head.left && R == head.right && lmax < head.value && rmin > head.value) ? lsize + rsize + 1 : 0;
  59. int maxSize = Math.max(msize, Math.max(lsize, rsize));
  60. Node root = lsize > rsize ? L : R;
  61. if (msize == maxSize) root = head;
  62. rec[0] = maxSize;
  63. rec[1] = Math.min(head.value, Math.min(lmin, rmin));
  64. rec[2] = Math.max(head.value, Math.max(lmax, rmax));
  65. return root;
  66. }
  67. //建立二叉树
  68. static Node build(int[] arr, int index) {
  69. if (index >= arr.length || arr[index] == -1) return null;
  70. Node root = new Node(arr[index]);
  71. root.left = build(arr, index * 2 + 1);
  72. root.right = build(arr, index * 2 + 2);
  73. return root;
  74. }
  75. /**
  76. * @param head 传入的节点
  77. * @param height   层数(根节点为0)
  78. * @param to 表示的特定节点 H表示根节点 ^表示父亲节点在左上方 v表示父亲节点在左下方
  79. * @param len    指定每一个节点打印的宽度
  80. */
  81. static void printTree(Node head, int height, String to, int len) {
  82. if (head == null) return;
  83. printTree(head.right, height + 1, "v", len);
  84. String val = to + head.value + to; //两边指示的字符
  85. int lenV = val.length();
  86. int lenL = (len - lenV) / 2; //左边的空格(分一半)
  87. int lenR = len - lenV - lenL; // 右边的空格
  88. System.out.println(getSpace(len * height) + getSpace(lenL) + val + getSpace(lenR));
  89. printTree(head.left, height + 1, "^", len);
  90. }
  91. //获取指定的空格
  92. static String getSpace(int len) {
  93. StringBuffer str = new StringBuffer();
  94. for (int i = 0; i < len; i++) str.append(" ");
  95. return str.toString();
  96. }
  97. public static void main(String[] args) {
  98. int[] arr = {6, 1, 12, 0, 3, 10, 13, -1, -1, -1, -1, 4, 14, 20, 16, -1, -1, -1, -1, -1, -1, -1, -1, 2, 5, 11, 15, -1, -1, -1, -1};
  99. Node head = build(arr, 0);
  100. printTree(head, 0, "H", 10);
  101. System.out.println(biggestSubBST(head).value);
  102. System.out.println(biggestSubBST2(head).value);
  103. }
  104. }

二叉树打印见这个博客
测试效果:
image.png