求二叉樹中最大的二叉搜索子樹的頭節點

求二叉樹中最大的二叉搜索子樹的頭節點

作者:Grey

原文地址:

博客園:求二叉樹中最大的二叉搜索子樹的頭節點

CSDN:求二叉樹中最大的二叉搜索子樹的頭節點

題目描述

給定一棵二叉樹的頭節點head, 返回這顆二叉樹中最大的二叉搜索子樹的頭節點。

暴力解法

定義遞歸函數

TreeNode maxSubBSTHead1(TreeNode head)

遞歸含義表示:以head爲頭的二叉樹中最大的二叉搜索子樹的頭結點是什麼。

接下來是 base case,

    if (head == null) {
      return null;
    }

定義一個輔助函數getBSTSize(head),這個函數表示:如果以head爲頭的樹是二叉搜索樹,則返回其大小,否則返回 0。

getBSTSize(head)的實現思路也比較簡單,即通過中序遍歷收集以 head 爲頭的樹,如果這個樹滿足二叉搜索子樹,則返回二叉搜索子樹的大小,如果以 head 的頭不是二叉搜索樹,直接返回 0。

代碼如下

  public static int getBSTSize(TreeNode head) {
    if (head == null) {
      return 0;
    }
    ArrayList<TreeNode> arr = new ArrayList<>();
    // 中序遍歷收集以 head 爲頭的二叉樹,存在數組中
    in(head, arr);
    for (int i = 1; i < arr.size(); i++) {
      if (arr.get(i).val <= arr.get(i - 1).val) {
        return 0;
      }
    }
    return arr.size();
  }

實現瞭如上方法,主函數直接做如下調用即可,代碼說明見註釋:

  
  public static TreeNode maxSubBSTHead1(TreeNode head) {
    if (head == null) {
      return null;
    }
    // 以 head 爲頭的二叉搜索子樹大小不爲0,說明head這就是最大的二叉搜索子樹頭!
    if (getBSTSize(head) != 0) {
      return head;
    }
    // 去左樹上找哪個結點是最大二叉搜索子樹的頭結點
    TreeNode leftAns = maxSubBSTHead1(head.left);
    // 去右樹上找哪個結點是最大二叉搜索子樹的頭結點
    TreeNode rightAns = maxSubBSTHead1(head.right);
    // 左右樹哪個二叉搜索子樹更大,就返回哪個結點
    return getBSTSize(leftAns) >= getBSTSize(rightAns) ? leftAns : rightAns;
  }

二叉樹的遞歸套路

定義如下數據結構

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

    public Info(TreeNode h, int size, int mi, int ma) {
      maxSubBSTHead = h;
      maxSubBSTSize = size;
      min = mi;
      max = ma;
    }
  }

針對每一顆子樹,都有如上結構信息,其中

maxSubBSTHead: 表示某個子樹的最大二叉搜索子樹的頭結點

maxSubBSTSize: 表示某個結點如果是二叉搜索樹,其大小爲多少

min:表示以某個結點爲頭的樹的最小值是多少

max:表示以某個結點爲頭的樹的最大值是多少

接下來定義遞歸函數

Info process(TreeNode X)

以 X 爲頭的樹,返回對應的 Info

接下來整理可能性

  1. 如果 X == null 則直接返回 null,即 base case;

  2. 接下來問左樹要 Info 信息,再問右樹要 Info 信息,整合成 head 的 info 信息,以代碼註釋來說明

// 問左樹要信息
    Info leftInfo = process(X.left);
    // 問右樹要信息
    Info rightInfo = process(X.right);
    int min = X.val;
    int max = X.val;
    TreeNode maxSubBSTHead = null;
    int maxSubBSTSize = 0;
    
    if (leftInfo != null) {
      // 左樹信息不爲 null
      // 則 head.val 和 左樹的min PK,誰小誰是以head 爲頭的min 信息
      min = Math.min(min, leftInfo.min);
      // 則 head.val 和 左樹的max PK,誰大誰是以head 爲頭的max 信息
      max = Math.max(max, leftInfo.max);
      // 以 head 爲頭的最大二叉搜索子樹的頭結點至少是leftInfo.maxSubBSTHead
      maxSubBSTHead = leftInfo.maxSubBSTHead;
      // 以 head 爲頭的最大二叉搜索子樹的頭結點大小至少是leftInfo.maxSubBSTSize
      maxSubBSTSize = leftInfo.maxSubBSTSize;
    }
    if (rightInfo != null) {
      // 右樹信息不爲 null 
      // 思路和 左樹信息不爲 null 一樣
      min = Math.min(min, rightInfo.min);
      max = Math.max(max, rightInfo.max);
      if (rightInfo.maxSubBSTSize > maxSubBSTSize) {
        maxSubBSTHead = rightInfo.maxSubBSTHead;
        maxSubBSTSize = rightInfo.maxSubBSTSize;
      }
    }
    // 到了這一步,說明 leftInfo 和 rightInfo 至少有一個爲 null
    // 不管哪個爲null,如果要以 X 爲最大二叉搜索子樹的頭結點,則需要滿足以下條件
    // 1. leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.val
    // 2. rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.val
    if ((leftInfo == null || (leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.val))
        && (rightInfo == null || (rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.val))) {
      maxSubBSTHead = X;
      maxSubBSTSize =
          (leftInfo == null ? 0 : leftInfo.maxSubBSTSize)
              + (rightInfo == null ? 0 : rightInfo.maxSubBSTSize)
              + 1;
    }
    return new Info(maxSubBSTHead, maxSubBSTSize, min, max);

兩個思路完整代碼如下(含測試代碼)

import java.util.ArrayList;

public class Code_MaxSubBSTHead {

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

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

  public static int getBSTSize(TreeNode head) {
    if (head == null) {
      return 0;
    }
    ArrayList<TreeNode> arr = new ArrayList<>();
    in(head, arr);
    for (int i = 1; i < arr.size(); i++) {
      if (arr.get(i).val <= arr.get(i - 1).val) {
        return 0;
      }
    }
    return arr.size();
  }

  public static void in(TreeNode head, ArrayList<TreeNode> arr) {
    if (head == null) {
      return;
    }
    in(head.left, arr);
    arr.add(head);
    in(head.right, arr);
  }

  public static TreeNode maxSubBSTHead1(TreeNode head) {
    if (head == null) {
      return null;
    }
    if (getBSTSize(head) != 0) {
      return head;
    }
    TreeNode leftAns = maxSubBSTHead1(head.left);
    TreeNode rightAns = maxSubBSTHead1(head.right);
    return getBSTSize(leftAns) >= getBSTSize(rightAns) ? leftAns : rightAns;
  }

  public static TreeNode maxSubBSTHead2(TreeNode head) {
    if (head == null) {
      return null;
    }
    return process(head).maxSubBSTHead;
  }

  // 每一棵子樹
  public static class Info {
    public TreeNode maxSubBSTHead;
    public int maxSubBSTSize;
    public int min;
    public int max;

    public Info(TreeNode h, int size, int mi, int ma) {
      maxSubBSTHead = h;
      maxSubBSTSize = size;
      min = mi;
      max = ma;
    }
  }

  public static Info process(TreeNode X) {
    if (X == null) {
      return null;
    }
    Info leftInfo = process(X.left);
    Info rightInfo = process(X.right);
    int min = X.val;
    int max = X.val;
    TreeNode maxSubBSTHead = null;
    int maxSubBSTSize = 0;
    if (leftInfo != null) {
      min = Math.min(min, leftInfo.min);
      max = Math.max(max, leftInfo.max);
      maxSubBSTHead = leftInfo.maxSubBSTHead;
      maxSubBSTSize = leftInfo.maxSubBSTSize;
    }
    if (rightInfo != null) {
      min = Math.min(min, rightInfo.min);
      max = Math.max(max, rightInfo.max);
      if (rightInfo.maxSubBSTSize > maxSubBSTSize) {
        maxSubBSTHead = rightInfo.maxSubBSTHead;
        maxSubBSTSize = rightInfo.maxSubBSTSize;
      }
    }
    if ((leftInfo == null ? true : (leftInfo.maxSubBSTHead == X.left && leftInfo.max < X.val))
        && (rightInfo == null
            ? true
            : (rightInfo.maxSubBSTHead == X.right && rightInfo.min > X.val))) {
      maxSubBSTHead = X;
      maxSubBSTSize =
          (leftInfo == null ? 0 : leftInfo.maxSubBSTSize)
              + (rightInfo == null ? 0 : rightInfo.maxSubBSTSize)
              + 1;
    }
    return new Info(maxSubBSTHead, maxSubBSTSize, min, max);
  }

  // for test
  public static TreeNode generateRandomBST(int maxLevel, int maxValue) {
    return generate(1, maxLevel, maxValue);
  }

  // for test
  public static TreeNode generate(int level, int maxLevel, int maxValue) {
    if (level > maxLevel || Math.random() < 0.5) {
      return null;
    }
    TreeNode head = new TreeNode((int) (Math.random() * maxValue));
    head.left = generate(level + 1, maxLevel, maxValue);
    head.right = generate(level + 1, maxLevel, maxValue);
    return head;
  }

  public static void main(String[] args) {
    int maxLevel = 4;
    int maxValue = 100;
    int testTimes = 1000000;
    for (int i = 0; i < testTimes; i++) {
      TreeNode head = generateRandomBST(maxLevel, maxValue);
      if (maxSubBSTHead1(head) != maxSubBSTHead2(head)) {
        System.out.println("Oops!");
      }
    }
    System.out.println("finish!");
  }
}

更多

算法和數據結構筆記

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章