题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
思路:
(上周四大晚上在刷这道题,那天状态不好头晕眼花,敲完代码运行自己写的样例没正确,然后没管就睡了。。想不通,我思路明明是正确的。然后有阴影了,周末没刷,今天大早上起来debug。。结果发现。。是我的选择排序写错了orz,被在我意想不到以为正确的地方坑了。改完排序,运行样例正确,直接提交牛客网,居然AC了。。我还想到另一种解法来着,等我一并说一下)
首先理解题意,这是一棵二叉搜索树,搜索树是什么呢?搜索树就是它的左子树的所有值<根的值<右子树的值,
也就是说,搜索树的中序遍历就是已经排好序的一组数啦。
根据这个突破口,判断后序遍历是否正确。
1. 后序遍历最后一个值为根结点,取出根的值,
在中序遍历中找到根,那么中序遍历,根的左边就是左子树,右边是右子树;即 左子树 根 右子树
观察后序遍历,应该是 左子树 右子树 根 的顺序
2. 判断后序遍历是否正确要点:
中序遍历左子树个数 是否等于 后序遍历左子树个数
中序遍历右子树个数 是否等于 后序遍历右子树个数
后序遍历左子树的所有值 是否小于 中序遍历右子树的第一个值 (其实只判断这个条件就行,为什么?自己慢慢想,就能想到了 : 因为这个条件可以包含验证前面的)
然后递归。
以上条件有一个不满足,就输出false
方法一:
直接构建左右子树进行递归
package com.xxxx;
/**
* create by ziqiiii
*/
public class Example {
static public void main(String[] args) {
int [] sequence = {2,4,3,6,8,9,5};
System.out.println(VerifySquenceOfBST(sequence));
}
//输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
//因为是二叉搜索树,所以我们知道,它的中序遍历是从小到大有序排列的
static public boolean VerifySquenceOfBST(int [] sequence) {
int len = sequence.length;
if(len <= 0){
return false;
}
int[] inOrder = new int[len];
for(int i =0;i<len;i++){
inOrder[i]=sequence[i];
}
for(int i =0;i<len;i++){ //选择排序
int min = inOrder[i];
int minIndex = i;
for(int j =i+1;j<len;j++){
if(inOrder[j]<min){
min = inOrder[j];
minIndex = j;
}
}
inOrder[minIndex] = inOrder[i];
inOrder[i]=min;
}
return isBST(inOrder,sequence); //递归判断是不是二叉搜索树
}
static public boolean isBST(int[] inOrder,int[]sequence){
int len = inOrder.length;
if(len == 0){
return true;
}
int root = sequence[len -1]; //后序遍历最后一个值是根
int leftLen = 0;
while(inOrder[leftLen]<root){ //左子树的个数
leftLen++;
}
if(leftLen+1<len){ //有右子树
int rightMin = inOrder[leftLen+1]; //中序遍历右子树第一个值为最小值
for(int i =0;i<leftLen;i++){ //搜索树中,后序遍历的左子树所有值 应该小于 中序遍历右子树的最小值
if(sequence[i]>=rightMin){ //这里>=中的等于,是因为(假设输入的数组的任意两个数字都互不相同)
return false;
}
}
}
int[] leftInOrder = new int[leftLen]; //构建左子树的中序遍历数组
int[] leftSequence = new int[leftLen];//构建左子树的后序遍历数组
for(int i =0;i<leftLen;i++){
leftInOrder[i]=inOrder[i];
leftSequence[i]=sequence[i];
}
boolean res = isBST(leftInOrder,leftSequence); //递归检查,左子树
if(res==false){
return false;
}
int rigthtLen = len - leftLen - 1;
int[] rightInOrder = new int[rigthtLen]; //构建右子树的中序遍历数组
int[] rightSequence = new int[rigthtLen]; //构建右子树的后序遍历数组
for(int i =0;i<rigthtLen;i++){
rightInOrder[i]=inOrder[i+leftLen+1]; //+1是根的个数
rightSequence[i]=sequence[i+leftLen];
}
res = isBST(rightInOrder,rightSequence); //递归右子树
if(res == false){
return false;
}
return true;
}
}
牛客网运行:
方法二:
不直接构建左右子树,
传递左右子树开始下标和长度,递归:
注意下标的选取:
package com.xxxx;
/**
* create by ziqiiii
*/
public class Example {
static public void main(String[] args) {
int[] sequence = {5, 4, 3, 2, 1}; //true
System.out.println(VerifySquenceOfBST(sequence));
}
//输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
//因为是二叉搜索树,所以我们知道,它的中序遍历是从小到大有序排列的
static public boolean VerifySquenceOfBST(int[] sequence) {
int len = sequence.length;
if (len <= 0) {
return false;
}
int[] inOrder = new int[len];
for (int i = 0; i < len; i++) {
inOrder[i] = sequence[i];
}
for (int i = 0; i < len; i++) { //选择排序
int min = inOrder[i]; //min为当前最小值
int minIndex = i; //最小值所对应的index
for (int j = i + 1; j < len; j++) {
if (inOrder[j] < min) {
min = inOrder[j];
minIndex = j;
}
}
inOrder[minIndex] = inOrder[i]; //对换当前值与最小值
inOrder[i] = min;
}
return isBST(inOrder, 0, sequence, 0, len); //递归判断是不是二叉搜索树
}
// inOrder:中序遍历数组,inStart:中序遍历开始数组下标,sequence:后序遍历数组, postStart:后序遍历开始数组下标,len:子树长度
static public boolean isBST(int[] inOrder, int inStart, int[] sequence, int postStart, int len) {
if (len == 0 || len == 1) { //子树长度只有0或1个时返回true
return true;
}
int root = sequence[postStart + len - 1]; //根
int i = inStart;
for (; i < inStart + len && inOrder[i] != root; i++) ; //在中序遍历子树数组找根
if (inOrder[i] != root) { //在中序遍历里没有找到根
return false;
}
int lenL = i - inStart; //左子树长度
int lenR = len - 1 - lenL; //右子树长度
boolean res = true;
if (lenL != 0) { //左子树存在
res = isBST(inOrder, inStart, sequence, postStart, lenL);
if (res == false) {
return false;
}
}
if (lenR != 0) { //右子树存在
int minR = inOrder[inStart + lenL + 1];
for (int j = postStart; j < postStart + lenL; j++) {
if (sequence[j] > minR) {
return false;
}
}
inStart = inStart + lenL + 1; //注意这里的inStart,应该是inOrder子树数组开始下标+该左子树长度+根长度
postStart = postStart + lenL; //注意这里的postStart,应该是postOrder子树数组开始下标+该左子树长度
res = isBST(inOrder, inStart, sequence, postStart, lenR);
if (res == false) {
return false;
}
}
return true;
}
}