二叉树的后序遍历

Problem

输入: 一个整数数组(假设输入的数组的任意两个数字都互不相同)
任务:判断该数组是不是某二叉搜索树的后序遍历结果
返回:布尔值
在这里插入图片描述

递归分治
思路
划分左右子树

遍历数组arr [i, j]区间元素,寻找第一个大于根节点的节点arr[x] ,划分左子树区间 [i,x-1]右子树区间 [x, j - 1],根节点 j

判断是否满足二叉搜索树条件

条件: 左子树中所有节点的值 < 根节点的值;右子树中所有节点的值 > 根节点的值
因左子树必满足,只需判断右子树

终止条件

i≥j,遍历结束

answer
/**
 * @param {number[]} arr
 * @return {boolean}
 */
var verifyPostorder = function(arr) {
	if(!arr) return false;
	return recur(arr, 0, arr.length-1);
};
// 定义递归函数
var recur = (arr, i, j) => {
	if(i>=j) return true;
	let x = i;
	while (arr[x] < arr[j]) x++; // 寻找第一个大于根结点的位置
	for(let k = x; k<j; k++){
		if(arr[k] < arr[j]) return false; // 右子树只要出现小于根结点的节点就中断不符合要求
	}
	return recur(arr, i, x-1) && recur(arr, x,j-1)
}
辅助单调栈
思路

为了方便分析,将后续遍历结果倒着看:

后续遍历结果:[3,6,5,9,8,11,13,12,10] ==> [10,12,13,11,8,9,5,6,3]

arr[i]<arr[i+1]

挨着的两个数如果arr[i]<arr[i+1],那么arr[i+1]一定是arr[i]的右子节点。

因为比arr[i]大的肯定都是他的右子节点,如果还是挨着他的,肯定是在后续遍历中所有的右子节点最后一个遍历的,所以他一定是arr[i]的右子节点。

arr[i]>arr[i+1]

如果arr[i]>arr[i+1],那么arr[i+1]一定是arr[0]……arr[i]中某个节点的左子节点,并且这个值是大于arr[i+1]中最小的。

比如13,11是降序的,那么11肯定是他前面某一个节点的左子节点,并且这个值是大于11中最小的,我们看到12和13都是大于11的,但12最小,所以11就是12的左子节点。

辅助栈

综上,可使用栈来解决

遍历数组的所有元素,如果栈为空,就把当前元素压栈。如果栈不为空,并且当前元素大于栈顶元素,那么就说明当前元素是栈顶元素的右子节点,把当前元素压栈。当前元素小于栈顶元素,说明当前元素是某个节点的左子节点,我们目的是要找到这个左子节点的父节点,就让栈顶元素出栈,直到栈为空或者栈顶元素小于当前值为止,其中最后一个出栈的就是当前元素的父节点。

answer
/**
 * @param {number[]} postorder
 * @return {boolean}
 */
var verifyPostorder = function(arr) {
	if(!arr) return false;
	let stack = [], parent = Math.max;
	for(let i = arr.length-1; i>=0; i--){
        //当如果前节点小于栈顶元素,左子树,找父节点[知道找到最小的大于自身的数]
		while(stack.length>0 && arr[i] < stack[stack.length-1]) { // 注意此时同层级的右子树必然已经在栈里了
            parent = stack.pop();
        }
        if(arr[i] > parent) { //难理解结合图看
            return false;
        }
        stack.push(arr[i])
	}
	return true;
};
拓展

题目改为判断该数组是不是某二叉搜索树的后序遍历结果?

只需要判断数组是否有序就行了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咩咩羊10

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值