1. 程式人生 > 實用技巧 >演算法與資料結構-樹-簡單-二叉搜尋樹中的眾數

演算法與資料結構-樹-簡單-二叉搜尋樹中的眾數

二叉搜尋樹中的眾數

題目

leetcode原題:501. 二叉搜尋樹中的眾數

給定一個有相同值的二叉搜尋樹(BST),找出 BST 中的所有眾數(出現頻率最高的元素)。

假定 BST 有如下定義:

  • 結點左子樹中所含結點的值小於等於當前結點的值
  • 結點右子樹中所含結點的值大於等於當前結點的值
  • 左子樹和右子樹都是二叉搜尋樹

提示:如果眾數超過1個,不需考慮輸出順序

進階:你可以不使用額外的空間嗎?(假設由遞迴產生的隱式呼叫棧的開銷不被計算在內)

分析

樹的題目要求眾數,那麼求眾數的基礎就是遍歷樹+儲存中間值,最後返回眾數,乍一看蠻簡單。但進階中的需求提到,儘量不使用額外的空間,意思是不使用map能不能做到?

一般來說,解題分為兩種思路:

  • 蠻力遍歷,儲存中間值,通過儲存下來的中間值計算輸出需要的結果。
  • 通過某種方式使得資料有序,在有序的基礎上去思考如何不使用額外空間,僅使用O(1)的空間複雜度來解決問題。

首先思考如何有序遍歷

題目有一個特殊的條件,這個樹為二叉搜尋樹,二叉搜尋樹本身是一定程度有序的,左子樹一定小於等於根節點,右子樹一定大於等於根節點,那麼如何通過遍歷讓節點有序輸出呢?考慮樹的三種遍歷方式,中序遍歷可以實現這個需求!

然後思考如何使用O(1)的空間複雜度來求得眾數。

思考到這裡,題目就轉變為了如果給你一個有序陣列,如何使用O(1)空間複雜度求得眾數。

考慮一個具體問題:[-1,0,1,1,2,3]

遍歷到-1時,眾數結果陣列為[-1],maxCount=1,依次類推,遍歷到第一個1之後,眾數陣列為[-1,0,1],maxCount依舊為1,接著遍歷第二個1,這時發現1的個數為2,大於maxCount,所以需要清空陣列,重新把1放進去,並更新maxCount為2,下面的2和3都因為個數小於maxCount不會被加入眾數陣列中,至此遍歷結束。

分析上面的思路,我們需要三個int變數,一個記錄了上次遍歷資料,一個記錄了上次資料的連續個數,另外一個記錄了maxCount。

這樣大框架就出來了!

總結一下這部分:

  • 中序遍歷使得從小到大有序
  • 利用三個int變數記錄中間結果,達到O(1)的時間複雜度

程式碼

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {

    private List<Integer> resultList = new ArrayList<>();
    private int lastNumber;
    private int lastCount;
    private int maxCount;
    
    public int[] findMode(TreeNode root) {
        middleTree(root);

        int[] result = new int[resultList.size()];
        for(int i = 0;i<=resultList.size()-1;i++){
            result[i] = resultList.get(i);
        }
        return result;
    }

    private void middleTree(TreeNode root){
        if(root == null){
            return;
        }
        middleTree(root.left);
        updateList(root.val);
        middleTree(root.right);
    }

    private void updateList(int val){
        if(resultList.size() == 0){
            lastNumber = val;
            lastCount = 1;
            maxCount = 1;
            resultList.add(val);
        }else{
           if(val == lastNumber){
               lastCount++;
           }else{
               lastNumber = val;
               lastCount = 1;
           }

           if(lastCount > maxCount){
              //清空原來list
              resultList.clear();
              //加入
              resultList.add(val);
              //更新maxCount 為 lastCount
              maxCount = lastCount;
           }else if(lastCount == maxCount){
               //加入
               resultList.add(val);
           }else{
               //不加入
           }
        }
    }
}