題目連結:https://leetcode.cn/problems/validate-binary-search-tree/description/
題目敘述:
給你一個二叉樹的根節點 root ,判斷其是否是一個有效的二叉搜尋樹。
有效二叉搜尋樹定義如下:
- 節點的左子樹只包含 小於 當前節點的數。
- 節點的右子樹只包含 大於 當前節點的數。
- 所有左子樹和右子樹自身必須也是二叉搜尋樹。
示例 1:
輸入:root = [2,1,3]
輸出:true
示例 2:
輸入:root = [5,1,4,null,null,3,6]
輸出:false
解釋:根節點的值是 5 ,但是右子節點的值是 4 。
提示:
樹中節點數目範圍在[1, 10^4] 內
-2^31 <= Node.val <= 2^31 - 1
思路:
二叉搜尋樹是一顆有序的樹,我們可以利用這個很有用的性質
我們知道二叉樹的每個結點,它的左子樹上的所有結點都小於這個結點,它的右子樹上的所有結點都大於這個結點
那麼我們使用中序遍歷,將這個二叉搜尋樹中的元素全部存取到陣列中,這個陣列就是有序的了(如果是二叉搜尋樹的話)
那麼現在我們就轉化成了判斷一個陣列的序列是否有序了
程式碼:
class Solution {
public:
void traversal(TreeNode* root, vector<int>& vec) {
if (root == NULL) return;
//處理左子樹
traversal(root->left, vec);
//處理中的邏輯
vec.push_back(root->val);
//處理右子樹
traversal(root->right, vec);
}
bool isValidBST(TreeNode* root) {
vector<int> vec;
traversal(root, vec);
for (int i = 1; i < vec.size(); i++) {
//找到了無序的序列,就直接返回false
if (vec[i] <= vec[i - 1]) return false;
}
//否則,返回true
return true;
}
};
另一種方法
其實,這題我們可以不使用陣列來記錄所有的結點,可以使用一個指標,用來記錄上一個訪問過的結點,然後比較上一個結點和當前結點的大小,如果不同,就直接返回false,相同則
呼叫遞迴函式比較左右子樹,如果左右子樹有一個為false,則為false,否則就是true
程式碼
class Solution {
public:
TreeNode*pre=NULL;
bool isValidBST(TreeNode* root) {
if(root==NULL) return true;
//遞迴處理左子樹
int left=isValidBST(root->left);
//如果上一個結點大於當前結點,返回false
if(pre!=NULL&&pre->val>=root->val) return false;
//更新pre的值
pre=root;
int right=isValidBST(root->right);
//left和right有一個為假,就是假
return left&&right;
}
};
迭代法
這題迭代法的程式碼與第二種的思路很像,也是使用一個指標來儲存上一個結點的值
迭代法程式碼:
class Solution {
public:
bool isValidBST(TreeNode* root) {
if(root==NULL) return true;
stack<TreeNode*> st;
TreeNode*pre=NULL;
TreeNode*cur=root;
while(!st.empty()||cur!=NULL){
if(cur!=NULL){
st.push(cur);
cur=cur->left;
}
else{
cur=st.top();
st.pop();
//找到比上一個結點大的結點,直接返回false
if(pre!=NULL&&pre->val>=cur->val) return false;
pre=cur;
cur=cur->right;
}
}
return true;
}
};