题目描述:
输入一个整数数组,判断该数组是否为某二叉搜索树的后序遍历序列,是则返回true,否则返回false,输入的数组中任意两数互不相同。
解题核心:
二叉搜索树的左子树的所有结点的值都比根结点小,右子树的所有结点的值都比根结点大。
解题思路:
以下列二叉树为例:
该二叉树的后序遍历序列为:
1(左子树) | 3(左子树) | 2(左子树) | 6(右子树) | 5(根节点) |
二叉树后序遍历的特性为:[ 左子树 | 右子树 | 根节点 ],由于二叉搜索树的左子树中的任意结点的值比根节点的值小,右子树中的任意结点值比根节点的值大,我们可以得知,一个正确的二叉搜索树后序遍历序列中,序列的最后一项一定是根节点对应的值,再从左往右遍历序列,找到第一个比最右侧元素(根节点对应元素)的值大的元素,这个元素便是右子树的一部分,而从序列最左侧元素到这个元素的前一个元素形成的序列便是左子树的序列,这个元素开始直到根节点的前一个元素形成的序列便是右子树的序列。
由于二叉树本身的结构特点,二叉树是一个天然适合使用分治法解决问题的数据结构,本题也是如此,在划分左右子树的序列以后递归操作判断。
函数设计:
返回类型:
bool
参数:
int beginIndex,序列第一个元素的索引。
int root,当前树的根节点(最后一个元素的索引)。
vector<int> tree,待检验的序列。
递归出口:
当子树的序列的第一个元素索引大于等于根节点元素索引时说明该子树的结点数量不大于1,说明该子树合法,返回true。
while循环遍历,找到当前序列中第一个比根结点元素值大的元素索引(若无该元素,将会找到根节点的前一个元素,接下来的for循环也不会进行)。再用for循环,从刚刚找到的索引出发,一直遍历到根节点,若找到一个值比根节点元素小的元素则说明当前序列不是二叉搜索树的后序遍历,返回false。
递归实现:
通过返回值来判断左右子树对应的序列的合法性,由于左右子树都应满足该规则,故两个递归函数之间应以&&连接。
代码实现:
C++:
bool search(int beginIndex,int root,vector<int> tree)
{
//若起始点大于根的位置则说明该子树的节点个数<=1,返回true
if(beginIndex >= root)
return true;
//找到除根以外的第一个最大值
int rightChildIndex = beginIndex;
while(rightChildIndex < root && tree[rightChildIndex] < tree[root])
rightChildIndex ++;
//从右子树的起点开始寻找,若找到比根节点小的值返回false
for(int i = rightChildIndex ; i < root ; i++)
if(tree[i] < tree[root])
return false;
//通过返回来递归查找左右子树
return search(beginIndex,rightChildIndex - 1,tree) && search(rightChildIndex,root - 1,tree);
}