题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
解题思路
1、二叉搜索树 又叫 二叉排序树,是一个递归的树型结构:
如果根结点为空,返回false;
根结点的左孩子结点值小于根结点,根结点右孩子结点值大于根结点。
根结点的左右子树分别满足上述条件。
中序遍历二叉搜索树可得到递增的序列。
2、判断一个二叉树后序遍历序列是否为二叉搜索树,必须满足数组前半部分序列小于数组的最后一位数(根结点值),后半部分序列(除去最后一个结点)大于数组的最后一个元素,而且其每个部分的序列也要满足以上条件。
3、可用如下4种方法(实则2种 递归 非递归)解答此题。
代码实现
1、 由于需要标记数组序列中的左子树序列范围和右子树序列的范围,故需要重新定义函数将数组下标的参数加入到函数之中。
由于该函数为bool类型,定义两个bool变量来接收左子树序列和右子树序列的真假性,由于函数体中只给定了出现false的情况,没有直接对true的情况进行判断,所以两个变量的初始化为true,如果整个数组序列没有返回false并且左右子树也没有返回false的话,函数体便会返回两个bool变量的初试值——true,否则返回false。
由于二叉树不一定为完全二叉树或者是满二叉树,在递归的过程中,可能出现分枝树中为单支树的情况,必须对数组下标的越界问题进行判断,在出现单支树的情况下,是可以出现左子树或者是右子树为空的情况,此时若不进行判断,则会在下一轮进入递归函数中执行if (sequence.empty()) return false;
直接返回false,导致误判。
class Solution
{
//第一个函数为自定义函数
bool VerifyVectorOfBST(vector<int> sequence, int start, int end)//int 为数组下标
{
int i = 0, j = 0;
for (i = 0; i < end; i++)
{
if (sequence[i] > sequence[end])
{
break;
}
}
for (j = i; j < end; j++)
{
if (sequence[j] < sequence[end])
{
return false;
}
}
bool leftBST = true, rightBST = true; // 先定义好true类型
if (i > start)
{
leftBST = VerifyVectorOfBST(sequence, start, i - 1); //判断数组下标是否越界
}
if (i < end - 1)
{
rightBST = VerifyVectorOfBST(sequence, i, end - 1);
}
return leftBST && rightBST;
}
bool VerifySquenceOfBST(vector<int> sequence) {
if (sequence.empty())
{
return false;
}
return VerifyVectorOfBST(sequence, 0, sequence.size() - 1); // 数组下标
}
}
2、 可以使用迭代器来标记动态数组中左子树和右子树边界的下标,进而实现函数的递归,思路和方法1一致。
bool VerifySquenceOfBST(vector<int> sequence) // 可以使用迭代器
{
if (sequence.empty())
return false;
vector<int>::iterator itFirst = sequence.begin(), itLast;
for (; itFirst < sequence.end() - 1; itFirst++)
{
if (*itFirst > *(sequence.end() - 1))
{
break;
}
}
for (itLast = itFirst; itLast < sequence.end() - 1; itLast++)
{
if (*itLast < *(sequence.end() - 1))
{
return false;
}
}
bool leftTree = true, rightTree = true;;
if (itFirst > sequence.begin())
{
leftTree = VerifySquenceOfBST(vector<int>(sequence.begin(), itFirst)); // 这一个重要的语法知识
}
if (itLast < sequence.end() - 1)
{
rightTree = VerifySquenceOfBST(vector<int>(itFirst, sequence.end() - 1));
}
return leftTree && rightTree;
}
重要语法知识: 相当于动态数组下标范围
leftTree = VerifySquenceOfBST(vector<int>(sequence.begin(), itFirst));
3、 新建两个vector容器去存储数组中的左右子树,进入新的递归函数,思路与1、2一致。
bool VerifySquenceOfBST(vector<int> sequence) // 记得考虑数组下标不能越界
{
if (sequence.empty())
{
return false;
}
int i = 0, j = 0;
vector<int> preV, postV;
for (; i < sequence.size() - 1; i++)
{
if (sequence[i] < sequence.back())
{
preV.push_back(sequence[i]);
}
else
{
break;
}
}
for (j = i; j < sequence.size() - 1; j++)
{
if (sequence[j] > sequence.back())
{
postV.push_back(sequence[j]);
}
else
{
return false;
}
}
bool leftTree = true, rightTree = true;
if (i > 0)
{
leftTree = VerifySquenceOfBST(preV);
}
if (i < sequence.size() - 1)
{
rightTree = VerifySquenceOfBST(postV);
}
return leftTree && rightTree;
}
4、 非递归法
这个思路的构思就很巧妙了,首先将length等于数组的长度,在每次循环减1的过程中,如果保证了树的左子树小于根结点,右子树大于根结点,根结点不存在时,左子树小于右子树,符合二叉搜索树的定义。
bool VerifySquenceOfBST(vector<int> sequence)
{
int i = 0;
int length = sequence.size();
if (length == 0)
{
return false;
}
while (--length)
{
while (sequence[i++] < sequence[length]);
while (sequence[i++] > sequence[length]);
if (i < length)
{
return false;
}
i = 0;
}
return true;
}
放上主函数,以便在自己电脑的IDE上运行。
void main()
{
vector<int> sequence;
sequence.push_back(4);
sequence.push_back(6);
sequence.push_back(7);
sequence.push_back(5);
cout << VerifySquenceOfBST(sequence) << endl; // 1
system("pause");
return;
}
总结
涉及到bool类型的递归函数,有如下感想:
首先要对所给参数的合法性进行判断。
函数体中要对返回值为true和false进行明确的声明。
递归函数要么作为返回值,要么在判断语句中,要么指向bool类型的变量并最终返回该变量。
考虑问题要全面,比如二叉树类型,在递归中要求对参数是否合法进行判断,递归函数中参数的合法性有可能和主函数参数的合法性不同,视情况而定。