❓剑指 Offer 33. 二叉搜索树的后序遍历序列
难度:中等
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true
,否则返回 false
。假设输入的数组的任意两个数字都互不相同。
参考以下这颗二叉搜索树:
5
/ \
2 6
/ \
1 3
示例 1:
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
提示:
- 数组长度 <= 1000
💡思路:递归
后序遍历 和 前序遍历 的特点一样,唯一不同的就是根结点一个在前,一个在后!
又有二叉搜索树的性质,二叉搜索树是有序的,对每一个树:
- 左子树上所有结点的值都 小于 根节点的值;
- 右子树上所有结点的值都 大于 根节点的值。
所以只要知道 根节点 就能确定哪些结点属于左子树,哪些属于右子树;而后序遍历刚好能得到根节点:
- 所以先拿到序列的最后一个数,即为 根结点;
- 然后根据 二叉搜索树的性质,找到左右子树的分界点
flag
:- 从后往前遍历,找到第一个小于根节点的数,即为分界点
flag
; - 该分界点
flag
及其左边的应该都在左子树,左子树都应小于根节点,如果有不小于的根节点的数,则一定不是二叉搜索树,返回false
; - 如果分界点左边的数都小于根节点,则根据 分界点
flag
切成两部分,左子树 和 右子树,再分别判断,只有同时都是二叉搜索树时,才返回true
。
- 从后往前遍历,找到第一个小于根节点的数,即为分界点
🍁代码:(C++、Java)
C++
class Solution {
public:
bool verifyPostorder(vector<int>& postorder) {
if(postorder.size() == 0) return true;
return verify(postorder, 0, postorder.size() - 1);
}
bool verify(vector<int>& postorder, int fir, int lst){
if(fir >= lst) return true;
int flag = lst - 1;
while(flag >= fir && postorder[flag] > postorder[lst]){
flag--;
}
for(int i = flag - 1; i >= fir; i--){
if(postorder[i] > postorder[lst]) return false;
}
return verify(postorder, fir, flag) && verify(postorder, flag + 1, lst -1);
}
};
Java
class Solution {
public boolean verifyPostorder(int[] postorder) {
if(postorder.length == 0) return true;
return verify(postorder, 0, postorder.length - 1);
}
private boolean verify(int[] postorder, int fir, int lst){
if(fir >= lst) return true;
int flag = lst - 1;
while(flag >= fir && postorder[flag] > postorder[lst]){
flag--;
}
for(int i = flag - 1; i >= fir; i--){
if(postorder[i] > postorder[lst]) return false;
}
return verify(postorder, fir, flag) && verify(postorder, flag + 1, lst - 1);
}
}
🚀 运行结果:
🕔 复杂度分析:
- 时间复杂度:
O
(
n
2
)
O(n^2)
O(n2),每次调用
verify
减去一个根节点,最差该二叉树退化为链表,递归调用了n
次,且比较了n
次。 - 空间复杂度:
O
(
n
)
O(n)
O(n),递归调用栈,最差该二叉树退化为链表,深度为
n
。
题目来源:力扣。
放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我LeetCode主页 / CSDN—力扣专栏,每日更新!