方法一:递归分治
public boolean verifyPostorder(int[] postorder){
return Solve(postorder,0,postorder.length-1);
}
public boolean Solve(int[] postorder,int i,int j){
if(i>=j) return true;//表示此时子树结点<=1
int m=i;
while(postorder[m]<postorder[j]) m++;//找到左子树边界m-1
int n=m;
while(postorder[m]>postorder[j]) m++;//找到右子树边界m-1
return m==j&&Solve(postorder,i,n-1)&&Solve(postorder,n,j-1);
}
方法二:栈
思路:根据后序遍历的规律,倒序后序遍历,就可以得到root->right->left。观察倒序后的规律可得:
挨着的两个数如果arr[i]<arr[i+1],那么arr[i+1]一定是arr[i]的右子节点。
如果arr[i]>arr[i+1],那么arr[i+1]一定是arr[0]……arr[i]中某个节点的左子节点,并且这个值是大于arr[i+1]中最小的。
越往右子树遍历,值越大,如果一旦打破这一规律,就说明遍历到了左子树,为了确定这是谁的左子树,需要把右结点挨个遍历一遍,直到没有结点了或者遇到比左子树根结点小的右结点,遍历结束。这时就需要一个数据结构存储这些右结点,因此选择栈。而左子树的根结点就是最后弹出的那个结点,为了保存这个结点,设置变量prevElem。继续遍历后面的结点,后面的结点只有两类:左子树的子结点或其他结点的左子树子结点。但无论如何都应该比prevElem小,于是每个结点都和prevElem比较大小,并继续找左子树。
public boolean verifyPostorder(int[] postorder) {
Deque<Integer> stack = new LinkedList<>();
int pervElem = Integer.MAX_VALUE;
for (int i = postorder.length - 1;i>=0;i--){
if (postorder[i] > pervElem){
return false;
}
while (!stack.isEmpty() && postorder[i] < stack.peek()){
pervElem = stack.pop();
}
stack.push(postorder[i]);
}
return true;
}
方法三:单调栈
public boolean verifyPostorder(int[] postorder){
Stack<Integer> stack=new Stack<>();
int root=Integer.MAX_VALUE;
for(int i=postorder.length-1;i>=0;i--){
if(postorder[i]>root) return false;
while(!stack.isEmpty()&&stack.peek()>postorder[i]){
root=stack.pop();
}
stack.push(postorder[i]);
}
return true;
}