1. 程式人生 > >LeetCode 把二叉搜尋樹轉換為累加樹

LeetCode 把二叉搜尋樹轉換為累加樹

第538題


給定一個二叉搜尋樹(Binary Search Tree),把它轉換成為累加樹(Greater Tree),使得每個節點的值是原來的節點值加上所有大於它的節點值之和。

例如:

輸入: 二叉搜尋樹:
              5
            /   \
           2     13

輸出: 轉換為累加樹:
             18
            /   \
          20     13

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/convert-bst-to-greater-tree

概念

二叉搜尋樹

二叉查詢樹(Binary Search Tree),(又:二叉搜尋樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別為二叉排序樹。

中序遍歷

中序遍歷(LDR)是二叉樹遍歷的一種,也叫做中根遍歷、中序周遊。在二叉樹中,中序遍歷首先遍歷左子樹,然後訪問根結點,最後遍歷右子樹。

解題思路

  • 從定義我們知道,BST的中序遍歷為一個遞增序列
  • 我們將中序遍歷倒置(先右子樹,後根節點、再左子樹),即可實現一個遞減序列
  • 遍歷該序列,從大往小累加並更新節點值,即可實現累加樹(節點值=原來的節點值加上所有大於它的節點值之和)

程式碼實現

1.遞迴倒置中序遍歷思路實現

//遞迴實現
class Solution1 {
    public TreeNode convertBST(TreeNode root) {
        addSum(root, 0);
        return root;
    }

    public int addSum(TreeNode node, int parentVal) {
        //如果沒有節點了,返回父節點值
        if (node == null) {
            return parentVal;
        }

        //累加右邊所有節點值
        int rVal = addSum(node.right, parentVal);

        //當前節點值=右邊所有節點累加值+當前節點值
        node.val += rVal;
        //System.out.println("當前節點值:" + node.val);

        //累加左邊所有節點值
        int lVal = addSum(node.left, node.val);
        return lVal;
    }
}

2.利用堆疊,去遞迴化實現

//利用堆疊,去遞迴化
class Solution2 {
    public TreeNode convertBST(TreeNode root) {
        TreeNode oRoot = root;
        Stack<TreeNode> stack = new Stack();
        int sum = 0;
        while (true) {
            //右節點入棧
            while (root != null) {
                stack.push(root);
                root = root.right;
            }

            //如果棧為空退出迴圈
            if (stack.empty()) {
                break;
            }
            //否則出棧進入計算
            else {
                TreeNode node = stack.pop();
                //更新節點值
                node.val += sum;
                //更新sum值
                sum = node.val;
                //左節點進入[右節點入棧]
                root = node.left;
            }
        }
        //返回原樹,此時該樹所有節點已做更新
        return oRoot;
    }
}

總結

我們通過提交程式碼發現堆疊實現會比遞迴執行效率慢很多,這是因為:

  • 尾遞迴被jvm編譯器識別並針對其迭代對應進行優化處理過
  • 堆疊實現需要頻繁的push(入棧)、pop(出棧)操作導致效能下降

資料

  • 示例原始碼
  • 原文地址
  • Spring Boot、Spring Cloud 示例學習