演算法與資料結構-樹-簡單-二叉搜尋樹中的眾數
阿新 • • 發佈:2021-01-11
二叉搜尋樹中的眾數
題目
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{
//不加入
}
}
}
}