下面這個題雖然是二叉搜索樹,但本質上仍然是遍歷樹,並且中序遍歷二叉搜索樹是得到的排列是有序的,我們可以考慮用中序遍歷解決這一問題。
98. 驗證二叉搜索樹
假設一個二叉搜索樹具有如下特徵:
- 節點的左子樹只包含小於當前節點的數。
- 節點的右子樹只包含大於當前節點的數。
- 所有左子樹和右子樹自身必須也是二叉搜索樹。
示例 1:
輸入: 2 / \ 1 3 輸出: true
示例 2:
輸入: 5 / \ 1 4 / \ 3 6 輸出: false 解釋: 輸入爲: [5,1,4,null,null,3,6]。 根節點的值爲 5 ,但是其右子節點值爲 4 。
1、遞歸遍歷縮小區間
class Solution {
bool isValidBSThelper(TreeNode* root, long long low, long long high){
if(root == nullptr) return true;
//節點值嚴格在開區間內
if(root->val <= low || root->val >= high) return false;
return isValidBSThelper(root->left, low, root->val) && isValidBSThelper(root->right, root->val, high);
}
public:
bool isValidBST(TreeNode* root) {
//開始區間兩邊分到取到long所能表示的最大值和最小值
return isValidBSThelper(root, LONG_MIN, LONG_MAX);
}
};
2.利用BST中序遍歷的性質(遞歸做法)
class Solution {
//記錄中序遍歷root前一個節點的val,有點線索二叉樹的意思
long long pre = (long long)INT_MIN - 1;
public:
bool isValidBST(TreeNode* root) {
//空樹也是二叉搜索樹 或者 搜索到葉子節點就返回
if(root == nullptr){
return true;
}
//訪問BST的左子樹,如果左子樹不是BST,直接返回flase
if(!isValidBST(root->left)){
return false;
}
//遞歸回來之後,pre已是root左子樹中最大的元素
//判斷當前節點,是否滿足BST的性質
if(pre >= root->val){
return false;
}
//改變pre的值,準備訪問BST的右子樹
pre = root->val;
//訪問BST
return isValidBST(root->right);
}
};
3.利用BST中序遍歷的性質(非遞歸做法)
參考樹的遍歷
class Solution {
public:
bool isValidBST(TreeNode* root) {
//記錄中序遍歷root前一個節點的val
long long pre = (long long)INT_MIN - 1;
stack<TreeNode*> stack;
while(!stack.empty() || root != nullptr){
//一路向左下
while(root != nullptr){
stack.push(root);
root = root->left;
}
//此時棧頂爲左下節點,訪問完後,訪問右子樹
root = stack.top();
stack.pop();
//不滿足BST性質,結束
if(root->val <= pre){
return false;
}
pre = root->val;
//準備遍歷右子樹
//不要直接壓棧,萬一當前節點沒有右子樹呢
root = root->right;
}
return true;
}
};