LeetCode 98. 验证二叉搜索树
题意:判断一颗二叉树是否为有效的二叉搜索树。判断条件为:1.节点的左子树只包含 小于 当前节点的数;2.节点的右子树只包含 大于 当前节点的数;3.所有左子树和右子树自身必须也是二叉搜索树。
思路1:比较暴力的方案,将树进行一次遍历,使用深搜来进行遍历,深搜会遍历单独一条条支流,我们可以单独存储当前节点的那条支流上的节点,然后将当前节点跟前面的节点进行比较,如果有不符合的就不是二叉搜索树,反之成立。
例子:判断这棵树是否为二叉搜索树
从根节点开始,使用一个容器存储支流上的节点,存储的信息有节点数值和区分跟当前节点判断大还是小;
上图流程是先遍历到跟节点,容器是空的;接下来是遍历左子节点,左子节点2跟父子节点比较,因为是左边,所以2<5是符合的,然后将5放入到容器中,因为支流在5的左边,所以附加值是左;再进行左子节点的遍历,先判断子节点跟父子节点的大小,1<2是符合的,值1再跟容器中的5做比较,因为是左边,所以1<5也是符合的,然后将2放入容器中,附加值是左。
节点1的左右子节点都是空,返回到节点2,容器弹出数值2的信息;遍历到节点2的右子节点,右子节点3>2和容器里的值比较3<5也是符合,将2加入容器,附加值是右;节点3的左右子节点是空,返回节点2,弹出容器数值2的信息。
节点2左右节点遍历完,返回到节点5,弹出容器5的信息;遍历节点5的右子节点,8>5符合,将5加入容器,附加值是右;遍历节点8的左子节点,7<8与7>5符合,将8加入容器,附加值左;
节点7左右子节点为空,返回到节点8,弹出容器8的信息;遍历节点8的右子节点,9>8与9>5符合,将8加入容器,附加值是右;
基本整棵树遍历完成,都是符合要求,所以是一棵二叉搜索树。
实现代码:
class Solution {
public:
struct rootinfo{
bool blr;
int val;
};
void DFS(TreeNode* root, vector<rootinfo> rootvalue, bool& res) {
if(root == nullptr || res == false) {
return ;
}
if(root->left != nullptr) {
if(root->val <= root->left->val) {
res = false;
return ;
}
for(int i=0; i<rootvalue.size(); i++) {
bool br = rootvalue[i].blr == 0 ? root->left->val < rootvalue[i].val : root->left->val > rootvalue[i].val;
if(br == false) {
res = false;
return ;
}
}
rootinfo tmp;
tmp.val = root->val;
tmp.blr = 0;
rootvalue.push_back(tmp);
DFS(root->left, rootvalue, res);
rootvalue.pop_back();
}
if(root->right != nullptr) {
if(root->val >= root->right->val) {
res = false;
return ;
}
for(int i=0; i<rootvalue.size(); i++) {
bool br = rootvalue[i].blr == 0 ? root->right->val < rootvalue[i].val : root->right->val > rootvalue[i].val;
if(br == false) {
res = false;
return ;
}
}
rootinfo tmp;
tmp.val = root->val;
tmp.blr = 1;
rootvalue.push_back(tmp);
DFS(root->right, rootvalue, res);
rootvalue.pop_back();
}
}
bool isValidBST(TreeNode* root) {
bool bResult = true;
if(root == nullptr) {
return false;
}
vector<rootinfo> rootvalue;
rootvalue.clear();
DFS(root, rootvalue, bResult);
return bResult;
}
};
上述的方案比较暴力,直接判断每一个支流的节点数值。另外一个方案是对树进行一个中序遍历,如果是二叉搜索树,就是一个有序的数组。下面来进行中序遍历的遍历流程,也是以刚刚的树为例子
从跟节点开始遍历,节点5遍历左子节点2,再遍节点2的左子节点1,左子节点1的左右子节点都为空,放进数组;回退到节点2,将2放进数组;节点2左子节点已经遍历完,再遍历右子节点3,右子节点3的左右子节点都为空,将3放进数组;回退到节点2,节点2左右节点遍历完;
回退到节点5,将5放进数组;节点5的左子节点已经遍历完,再到右子节点8,到节点8的左子节点7,节点7的左右子节点都为空,将7放进数组;回退节点8,将8放进数组;
再到遍历节点8的右子节点9,节点9左右都为空,将9放进数组;基本遍历完成;
最后对数组进行比较,确定是从小到大排序,此树就为二叉搜索树。
其实中序遍历的遍历规则是先将左子节点放进数组,再到父节点放进数组,最后到右子节点放入数组,按此顺序遍历完整棵树。
实现代码:
class Solution {
public:
void DFS(TreeNode* root, vector<int>& resNum) {
if(root == nullptr) {
return ;
}
if(root->left != nullptr) {
DFS(root->left, resNum);
}
resNum.push_back(root->val);
if(root->right != nullptr) {
DFS(root->right, resNum);
}
}
bool isValidBST(TreeNode* root) {
bool bRes = true;
vector<int> resNum;
resNum.clear();
DFS(root, resNum);
for(int i=0; i<resNum.size()-1; i++) {
if(resNum[i] >= resNum[i+1]) {
bRes = false;
break;
}
}
return bRes;
}
};