從定義出發,理解二叉搜尋樹
阿新 • • 發佈:2018-11-19
[leetcode Validate Binary Search Tree]從定義出發,理解二叉搜尋樹
2015.12.13 12:53* 字數 855 閱讀 181評論 0喜歡 2
附上原題:
一棵二叉樹如果屬於二叉搜尋樹,必須滿足三個條件:
- 左子樹的所有節點都小於根節點
- 右子樹的所有節點都大於根節點
- 左子樹跟右子樹同時也是二叉搜尋樹
我們看到第三條定義本身也是遞迴的。那根據該定義,如何來檢驗一棵二叉樹到底是不是二叉搜尋樹?
首先,如果左子樹跟右子樹其中有一棵不是二叉搜尋樹的情況下,則該二叉樹必定不屬於二叉搜尋樹。那如何判定左子樹跟右子樹是不是二叉搜尋樹呢?好像我們又回到了原來的問題。看一種比較特殊的情況,假如說二叉樹只有一個節點,即沒有左子樹也沒有右子樹,那麼它必定屬於二叉搜尋樹。如果左子樹不存在,右子樹存在的情況下呢?此時左子樹就不需要再考慮是不是二叉搜尋樹了。反之右子樹不存在的情況下也一樣。
因此,對於這個問題,我們可以先考慮一棵二叉樹的葉子節點。比如說有這樣一棵二叉樹:
左子樹跟右子樹都屬於葉子節點,必定是二叉搜尋樹。在符合第三條定義的情況下,再來看前面兩條。根節點大於左子樹的所有節點,難道要用根節點與左子樹的每個節點去比較?我們換個角度想,是不是隻要根節點大於左子樹最大的節點就可以了?因為在確定左子樹屬於二叉搜尋樹的情況下,只要沿著左子樹的根節點出發一直向右即可找到最大的節點。同樣,對於第二個定義,根節點只需小於右子樹最小的節點即可。
我們運用了一種“分而治之”的思想,先考慮最基本的情況,即葉子節點,再得到左子樹和右子樹同時為二叉搜尋樹的前提下,用當前樹的根節點去比較左子樹的最大值和右子樹的最小值。然後演算法不斷得往上回溯,最終得出整棵樹是不是二叉搜尋樹。
根據以上分析,我們設計出如下演算法:
- 如果當前節點即不存在左子樹也不存在右子樹,直接返回true。
- 如果當前節點存在左子樹,則驗證左子樹是否為二叉搜尋樹,若是,並且根節點大於左子樹的最大值,則左子樹驗證通過。若左子樹不存在,同樣驗證通過。
- 如果當前節點存在右子樹,則驗證右子樹是否為二叉搜尋樹,若是,並且根節點小於右子樹的最小值,右子樹驗證通過。若右子樹不存在,同樣驗證通過。
- 若左子樹跟右子樹同時驗證通過,返回true;否則,返回false。
看程式碼:
class Solution { public: bool isValidBST(TreeNode* root) { bool isValidLeft = true; bool isValidRight = true; if (root) { int val = root->val; if (root->left) { //驗證左子樹是否為二叉搜尋樹,並且根節點大於左子樹的最小值 isValidLeft = isValidBST(root->left) && (val > fetchMaxNodeVal(root->left)); } if (root->right) { isValidRight = isValidBST(root->right) && (val < fetchMinNodeVal(root->right)); } if (!root->left && !root->right) { return true; } } return isValidLeft && isValidRight; } private: //獲取二叉樹的最大值 int fetchMaxNodeVal(TreeNode *node) { while (node->right) { node = node->right; } return node->val; } int fetchMinNodeVal(TreeNode *node) { while (node->left) { node = node->left; } return node->val; } };
小禮物走一走,來簡書關注我