方法一:分治思想:时间 O( n 2 n^2 n2),空间 O(n)
题解:
- 利用后序遍历的规则:左树 | 右树 | 根节点,将后序遍历序列分成一个个子树
- 检查每一颗子树是否满足二叉搜索树的特性:左树都比根节点小
- 如果都满足则说明数组正确
- 缺点:每次遍历数组都只能检测一个根节点,因此检查所有根节点需要O( n 2 n^2 n2)的时间
时间:遍历一次数组只能减少一个节点,而每次遍历都需要O(n)时间
空间:当二叉树退化成单只树则需要O(n)的空间
class Solution {
public:
bool verifyPostorder(vector<int>& postorder)
{
// 1.后序遍历的规则:左支|右支|根节点
// 2.因此只要满足每颗树都满足二叉搜索树的特性,则说明该数组正确
// 3.利用分治思想将二叉树划分成一颗颗子树
// 4.缺点:每次检查都要遍历二叉树,且一遍只能检查完成一个节点的正确性,时间复杂度O(n^2)
return CheckTree(postorder, 0, postorder.size());
}
bool CheckTree(vector<int>& postorder, int left, int right)
{
if (left >= right)
return true;
int i = left;
while (postorder[i] < postorder[right - 1])
i++;
int pos = i;
while (postorder[i] > postorder[right - 1])
i++;
return (i == right - 1) && CheckTree(postorder, left, pos) && CheckTree(postorder, pos, right - 1);
}
};
方法二:单调栈:时间 O(n),空间O(n)
题解:
- 后序遍历的倒序:根节点 | 右树 | 左树
- 利用一个栈专门存储搜索树的左树,也就是比根节点小的节点
- 只要栈不空,检测到当前节点比栈顶元素小,则说明到达了根节点子树的一个左子树
- 一直出栈,直到栈空 或者 栈顶元素大于当前节点
- 根节点为最后一次出栈元素
注:第一次 root 节点可以看作INT_MAX的左子树,而右子树为空
时间:所有节点都入栈出栈一次,因此是O(n)
空间:单支树空间O(n)
class Solution {
public:
bool verifyPostorder(vector<int>& postorder)
{
// 1.单调栈:借助一个栈结构专门存储搜索树的右子树,也就是比根节点大的树
// 2.只要栈不空,并且检测到当前节点比栈顶元素小,则说明到达了左子树
// 3.一直出栈,直到栈空 或者 栈顶元素小于当前节点
// 4.根节点为最后一次出栈元素
stack<int> stc;
int root = INT_MAX;
for (int i = postorder.size() - 1; i >= 0; --i)
{
if (postorder[i] > root)
return false;
while (!stc.empty() && stc.top() > postorder[i])
{
root = stc.top();
stc.pop();
}
stc.push(postorder[i]);
}
return true;
}
};