算法修煉之路—【字符串】Leetcode 783 二叉搜索樹節點最小距離

題目描述

給定一個二叉搜索樹的根節點root,返回樹中任意兩節點的差的最小值。

示例1:

輸入: root = [4, 2, 6, 1, 3, null, null]
輸出: 1
解釋: 注意,root是樹節點對象(TreeNode object),而不是數組。給定的樹可表示爲下圖:
在這裏插入圖片描述
最小的差值爲1,它是節點1和節點2的差值,也是節點3和節點2的差值。

注意:

  1. 二叉樹的大小範圍在2100
  2. 二叉樹總是有效的,每個節點的值都是整數,且不重複;
  3. 本題與530題相同;

思路分析

題目難度爲簡單 ,二叉搜索樹的特點爲節點坐邊的數值均小於本節點值;右子樹的值均大於本節點值,這裏需要求解任意兩節點的差的最小值,我們易知其最小值必出現在相鄰節點,故這裏直接思考:

  1. 根節點與左右節點的差值;
  2. 多個差值之間的比較,得出最小值;

這裏需要的就是遍歷樹,一個節點最多存在兩個可比較的值:root.val - root.left.val, root.right.val - root.val,題幹中給出樹的高度有限,故我們這裏採用簡單的遞歸解法,簡單來說就是:

  1. 判斷當前節點是否爲空,若爲空返回Integer.MAX_VALUE
  2. 判斷當前節點的左右節點是否均不存在,若是返回Integer.MAX_VALUE;
  3. 返回 當前節點的左右節點差值較小值和左右子樹的差值較小值 中的最小值,即爲輸出;

根據以上思考,我們給出核心的判斷代碼:

        if (root == null || (root.left == null && root.right == null)) {
            return Integer.MAX_VALUE;
        }
        
        int i1 = root.left == null ? Integer.MAX_VALUE : root.val - root.left.val;
        int i2 = root.right == null ? Integer.MAX_VALUE : root.right.val - root.val;
        
        int i3 = solutionRecursive(root.left);
        int i4 = solutionRecursive(root.right);
        
        return Math.min(Math.min(i1, i2), Math.min(i3, i4));

上面的寫法是爲了更好的理解,這裏我們進一步簡化代碼則有:

解題代碼

    public static int solutionRecursive(TreeNode root) {
        if (root == null || (root.left == null && root.right == null)) {
            return Integer.MAX_VALUE;
        }
        return Math.min(Math.min((root.left == null ? Integer.MAX_VALUE 
                                    : root.val - root.left.val), 
                                 (root.right == null ? Integer.MAX_VALUE 
                                    : root.right.val - root.val)),
                        Math.min(solutionRecursive(root.left), 
                                 solutionRecursive(root.right))
                        );

    }

複雜度分析

n爲樹的節點個數,h爲樹的高度:

時間複雜度: 這裏對每個節點進行了一次訪問,時間複雜度爲O(n);
空間複雜度: 沒有藉助輔助容器,但是因是遞歸解法,內存中存在棧空間的使用,故空間複雜度爲O(h)

小結

在本博客類似的算法文章中提過,樹這種數據類型特別適合遞歸求解,在現實業務場景中,樹的出現更多的用在檢索需求中,這就使得樹的高度不會太高;數據庫中甚至想要提高檢索效率使用如B樹、B+樹此類的多叉樹來減少I/O,從而提升系統效率和檢索速度; 這樣的也無需求催生下的樹結構,不會太高,這樣也爲遞歸這樣的算法求解方式提供了一定的適用條件和參考價值。

這裏簡單說一下適合遞歸的問題具有的特點:

  1. 總問題可以細分爲若干個有限的小問題,且小問題之間並沒有相干性;
  2. 總問題和小問題的求解方式是相同的;
  3. 確保遞歸的函數棧空間不會無限增長或超出題目要求;

Github源碼

完整可運行文件請訪問GitHub

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