[LeetCode] Largest BST Subtree 最大的二分搜尋子樹
Given a binary tree, find the largest subtree which is a Binary Search Tree (BST), where largest means subtree with largest number of nodes in it.
Note:
A subtree must include all of its descendants.
Here's an example:
10 / \ 5 15 / \ \ 1 8 7
The Largest BST Subtree in this case is the highlighted one.
The return value is the subtree's size, which is 3.
Hint:
- You can recursively use algorithm similar to 98. Validate Binary Search Tree at each node of the tree, which will result in O(nlogn) time complexity.
Follow up:
Can you figure out ways to solve it with O(n) time complexity?
這道題讓我們求一棵二分樹的最大二分搜尋子樹,所謂二分搜尋樹就是滿足左<根<右的二分樹,我們需要返回這個二分搜尋子樹的節點個數。題目中給的提示說我們可以用之前那道
解法一:
class Solution { public: int largestBSTSubtree(TreeNode* root) { int res = 0; dfs(root, res); return res; } void dfs(TreeNode *root, int &res) {if (!root) return; int d = countBFS(root, INT_MIN, INT_MAX); if (d != -1) { res = max(res, d); return; } dfs(root->left, res); dfs(root->right, res); } int countBFS(TreeNode *root, int mn, int mx) { if (!root) return 0; if (root->val <= mn || root->val >= mx) return -1; int left = countBFS(root->left, mn, root->val); if (left == -1) return -1; int right = countBFS(root->right, root->val, mx); if (right == -1) return -1; return left + right + 1; } };
下面我們來看一種更簡潔的寫法,對於每一個節點,都來驗證其是否是BST,如果是的話,我們就統計節點的個數即可,參見程式碼如下:
解法二:
class Solution { public: int largestBSTSubtree(TreeNode* root) { if (!root) return 0; if (isValid(root, INT_MIN, INT_MAX)) return count(root); return max(largestBSTSubtree(root->left), largestBSTSubtree(root->right)); } bool isValid(TreeNode* root, int mn, int mx) { if (!root) return true; if (root->val <= mn || root->val >= mx) return false; return isValid(root->left, mn, root->val) && isValid(root->right, root->val, mx); } int count(TreeNode* root) { if (!root) return 0; return count(root->left) + count(root->right) + 1; } };
題目中的Follow up讓我們用O(n)的時間複雜度來解決問題,我們還是採用DFS的思想來解題,由於時間複雜度的限制,只允許我們遍歷一次整個二叉樹,由於滿足題目要求的 二叉搜尋子樹必定是有葉節點的,所以我們的思路就是先遞迴到最左子節點,然後逐層往上遞迴,對於每一個節點,我們都記錄當前最大的BST的節點數,當做為左子樹的最大值,和做為右子樹的最小值,當每次遇到左子節點不存在或者當前節點值大於左子樹的最大值,且右子樹不存在或者當前節點值小於右子樹的最小數時,說明BST的節點數又增加了一個,我們更新結果及其引數,如果當前節點不是BST的節點,那麼我們更新BST的節點數res為左右子節點的各自的BST的節點數的較大值,參見程式碼如下:
解法三:
class Solution { public: int largestBSTSubtree(TreeNode* root) { int res = 0, mn = INT_MIN, mx = INT_MAX; bool d = isValidBST(root, mn, mx, res); return res; } bool isValidBST(TreeNode *root, int &mn, int &mx, int &res) { if (!root) return true; int left_n = 0, right_n = 0, left_mn = INT_MIN; int right_mn = INT_MIN, left_mx = INT_MAX, right_mx = INT_MAX; bool left = isValidBST(root->left, left_mn, left_mx, left_n); bool right = isValidBST(root->right, right_mn, right_mx, right_n); if (left && right) { if ((!root->left || root->val > left_mx) && (!root->right || root->val < right_mn)) { res = left_n + right_n + 1; mn = root->left ? left_mn : root->val; mx = root->right ? right_mx : root->val; return true; } } res = max(left_n, right_n); return false; } };
類似題目:
參考資料: