二叉搜索树的后序遍历序列
题目描述:
输入一个整数数组,判断该数组是不是某 二叉搜索树 的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。
例子:
5
/ \
2 6
/ \
1 3
输入: [1,6,3,2,5]
输出: false
示例 2:
输入: [1,3,2,6,5]
输出: true
提示:
数组长度 <= 1000
解法:
二叉搜索树的后序遍历序列是 左子树-> 右子树-> 根结点,且结点值满足如下关系式:
左子树结点值<根结点值<右子树结点值
因此采用递归判断处理。
具体逻辑如下:
对于一个二叉搜索树,如图所画的矩形框,把它分成不同的左右子树。每个子树又可以递归的划分成更小的子树,最终到某棵子树的结点为叶子节点时就可以完成全部判断。因此关键是把postorder数组中的不同元素按顺序对映到每个子树节点上,如图带箭头的线所示数组到树的元素映射。
dfs递归函数 中的参数 i 表示一棵树的最左边的叶子节点,参数 n 表示某棵子树的根节点到其最左边的叶子节点的距离,当n<=0时,说明前一个递归的子树满足了二叉搜索树的条件,因此到达递归临界点,返回true;
注意看dfs函数的内部:
- 首先计算得到根节点的值int v ,
(说明:dfs被调用时传入的参数n是整个数组的长度,而后进行递归分割成子树后,此时的n代表着子树的根节点到其最左边的叶子节点的距离,l两者本质上是一致的,因为可以假设一个原树根节点的虚拟父节点,则n就表示了这个虚拟父节点到最左叶子节点的距离,使得整个递归函数的逻辑自洽)
- 然后通过for循环找出第一个大于子树根节点的值,该点即上图中的根节点右子树的最左叶子节点(已亮黄色标出),显然,下一个递归的最左叶子结点对应数组的位置 j 找到了,因为 左子树结点值<根结点值<右子树结点值,即从j之后到i+n:即根节点之间的所有节点值必须大于根节点,否则不满足条件返回false。
代码如下:
class Solution {
public boolean verifyPostorder(int[] postorder) {
if (postorder == null || postorder.length < 2) {
return true;
}
return dfs(postorder, 0, postorder.length);
}
private boolean dfs(int[] postorder, int i, int n) {
if (n <= 0) {
return true;
}
int v = postorder[i + n - 1];
int j = i;
while (j < i + n && postorder[j] < v) {
++j;
}
for (int k = j; k < i + n; ++k) {
if (postorder[k] < v) {
return false;
}
}
return dfs(postorder, i, j - i) && dfs(postorder, j, n + i - j - 1);
}
}
本文含有隐藏内容,请 开通VIP 后查看