【剑指Offer-33】二叉搜索树的后序遍历序列
问题
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
示例
输入: [1,6,3,2,5]
输出: false输入: [1,3,2,6,5]
输出: true
解答1:递归
class Solution {
public:
vector<int> postorder;
bool verifyPostorder(vector<int>& postorder) {
this->postorder = postorder;
return recur(0, postorder.size() - 1);
}
bool recur(int i, int j) {
if (i > j - 2) return true; // 递归终止条件1
int cur = i; // cur初始值为最左端
while (postorder[cur] < postorder[j]) cur++;
int m = cur; // m为右子树起点
while (postorder[cur] > postorder[j]) cur++;// 检查右子树是否满足要求,cur!=j为递归终止条件2
return cur == j && recur(i, m - 1) && recur(m, j - 1);
}
};
重点思路
二叉搜索树的后序遍历特点为:假设遍历序列的长度为i
,则最右端为根节点,从左到右遍历,设第一个大于根节点的位置为m
,则[0, m-1]
部分为左子树,[m, i - 2]
部分为右子树。递归终止条件有两个,当遍历序列长度小于等于2时,必定符合要求;当右子树部分出现小于根节点的值时,必定不符合要求(在确定左子树时已经保证了那些值都小于根节点,所以只需要验证右子树就行)。
解答2:迭代(单调栈)
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
stack<int> s;
int parent = INT_MAX;
for (int i = postorder.size() - 1; i >= 0; i--) {
if (postorder[i] > parent) return false;
while (!s.empty() && postorder[i] < s.top()) {
parent = s.top();
s.pop();
}
s.push(postorder[i]);
}
return true;
}
};
重点思路
这里先说一下使用前中后序遍历验证二叉搜索树的做法。中序遍历最简单,只需要看遍历序列是不是严格单调递增就行;前序遍历使用递归和单调栈的做法很常见;而后序遍历的倒序是前序遍历的变种(根右左),同样也能使用单调栈。
这里说明前序遍历的单调栈做法。根据二叉搜索树的定义,左子树小于根节点。我们使用一个单调递减的单调栈,当遍历指向的元素大于栈顶值时,单调栈中存放的是该节点所有可能的根节点,栈中最后一个小于该节点的元素即其对应的根节点值。我们需要暂存这个根节点值,当这个根节点的右子树出现小于该暂存值的元素时,说明这不是二叉搜索树。