题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
题目来源:牛客网
算法分析
算法其实很简单,利用后序遍历的特性,根节点是在最后面的,那么我们找到了根节点之后,利用左子树的所有节点必定是小于它,右子树的所有节点必定是大于它的,可以将前面的数组分成两部分,两部分再递归操作就行了~
举个栗子
对于这个二叉搜索树:
它后序遍历的序列为[1, 4, 3, 6, 9, 8, 5],首先找到最后一个元素5,为整棵树的根节点,然后从前往后找,看看有没有第一个比5大的节点在哪,找到是6,于是将数组分成两部分:1)左子树[1, 4, 3];2)右子树[6, 9, 8]。注意这个问题是要求检验这个序列是否可能为后序遍历的序列,所以需要看看左子树的所有节点是否都小于根节点,同时所有右子树的节点是否都大于根节点。通过检查之后,再递归,分别对左子树、右子树进行是否可能为二叉搜索树后序遍历的序列的判断。
What’s More
原来题目的测试样例是错的(我发了纠错建议,不知道现在改过来了没),空树也是二叉树,所以输入空序列,应该输出true才对。
下面是(我觉得应该是)正确的写法,最后面是牛客网那种测试方法的写法:
class Solution {
public:
bool VerifySquenceOfBST(vector<int> seq) {
if (seq.empty())
return true;
int mid = findMiddle(seq), tail = seq.size() - 1;
// 检查左子树是否有大于根节点的情况
// 其实在计算mid的时候已经保证了左边这部分必定是小于根节点的
// 即这个循环只是用来示意需要关注这个性质是否成立而已,实际上是多余的
for (int i = 0; i < mid; ++i)
if (seq[i] > seq[tail])
return false;
// 检查右子树是否有小于根节点的情况
for (int i = mid; i < tail; ++i)
if (seq[i] < seq[tail])
return false;
bool left = VerifySquenceOfBST(vector<int>(seq.begin(), seq.begin()+mid));
bool right = VerifySquenceOfBST(vector<int>(seq.begin()+mid, seq.begin()+tail));
// 其实这里还可以利用&&的短路性质来加速判断,不必像上面这样写
// 直接写return left && Verify....
// 这样如果left为false的话,就可以直接少掉对右子树的判断了
return left && right;
}
int findMiddle(const vector<int>& seq) {
int tail = seq.size() - 1, key = seq[tail];
for (int i = 0; i < tail; ++i)
if (seq[i] > key)
return i;
return tail;
}
};
对于(我觉得是错误的)样例测试:
class Solution {
public:
bool VerifySquenceOfBST(vector<int> seq) {
if (seq.empty())
return false;
if (seq.size() == 1)
return true;
int mid = findMiddle(seq), tail = seq.size() - 1;
// 检查左子树是否有大于根节点的情况
for (int i = 0; i < mid; ++i)
if (seq[i] > seq[tail])
return false;
// 检查右子树是否有小于根节点的情况
for (int i = mid; i < tail; ++i)
if (seq[i] < seq[tail])
return false;
// 如果左子树为空或右子树为空,只需查找一边
if (mid == 0 || mid == tail)
return VerifySquenceOfBST(vector<int>(seq.begin(), seq.begin()+tail));
bool left = VerifySquenceOfBST(vector<int>(seq.begin(), seq.begin()+mid));
bool right = VerifySquenceOfBST(vector<int>(seq.begin()+mid, seq.begin()+tail));
return left && right;
}
int findMiddle(const vector<int>& seq) {
int tail = seq.size() - 1, key = seq[tail];
for (int i = 0; i < tail; ++i)
if (seq[i] > key)
return i;
return tail;
}
};