Given a binary search tree and the lowest and highest boundaries as L
and R
, trim the tree so that all its elements lies in [L, R]
(R >= L). You might need to change the root of the tree, so the result should return the new root of the trimmed binary search tree.
Example 1:
Input: 1 / \ 0 2 L = 1 R = 2 Output: 1 \ 2
Example 2:
Input: 3 / \ 0 4 \ 2 / 1 L = 1 R = 3 Output: 3 / 2 / 1
這道題讓我們修剪一棵二叉搜索樹,給了個邊界范圍[L, R], 所有不在這個范圍內的結點應該被移除掉,但是仍需要保留二叉搜索樹的性質,即左<根<右,有時候是小於等於。博主最開始的想法是先遍歷一遍二叉樹,將在返回內的結點值都放到一個數組后,遍歷結束后再根據數組重建一棵二叉搜索樹。這種方法會在某些test case上fail掉,可能會改變原來的二叉搜索樹的結構,所以我們只能換一種思路。正確方法其實應該是在遍歷的過程中就修改二叉樹,移除不合題意的結點。當然對於二叉樹的題,十有八九都是要用遞歸來解的。首先判斷如果root為空,那么直接返回空即可。然后就是要看根結點是否在范圍內,如果根結點值小於L,那么返回對其右子結點調用遞歸函數的值;如果根結點大於R,那么返回對其左子結點調用遞歸函數的值。如果根結點在范圍內,將其左子結點更新為對其左子結點調用遞歸函數的返回值,同樣,將其右子結點更新為對其右子結點調用遞歸函數的返回值。最后返回root即可,參見代碼如下:
解法一:
class Solution { public: TreeNode* trimBST(TreeNode* root, int L, int R) { if (!root) return NULL; if (root->val < L) return trimBST(root->right, L, R); if (root->val > R) return trimBST(root->left, L, R); root->left = trimBST(root->left, L, R); root->right = trimBST(root->right, L, R); return root; } };
下面這種方法是迭代的寫法,雖然樹的題一般都是用遞歸來寫,簡潔又美觀。但是我們也可以強行用while來代替遞歸,比如下面這種寫法:
解法二:
class Solution { public: TreeNode* trimBST(TreeNode* root, int L, int R) { if (!root) return NULL; while (root->val < L || root->val > R) { root = (root->val < L) ? root->right : root->left; } TreeNode *cur = root; while (cur) { while (cur->left && cur->left->val < L) { cur->left = cur->left->right; } cur = cur->left; } cur = root; while (cur) { while (cur->right && cur->right->val > R) { cur->right = cur->right->left; } cur = cur->right; } return root; } };
參考資料:
https://discuss.leetcode.com/topic/102034/java-solution-6-liner
https://discuss.leetcode.com/topic/104140/java-solution-iteration-version