[Leetcode] Verify Preorder Sequence in Binary Search Tree 验证先序序列
Verify Preorder Sequence in Binary Search Tree
Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary search tree.
You may assume each number in the sequence is unique.
Follow up: Could you do it using only constant space complexity?
栈法
复杂度
时间 O(N) 空间 O(N)
思路
二叉搜索树先序遍历序列的特点是降序的部分一定是向左走的,一旦开始升序说明开始向右走了,则上一个降序的点则限定了后面的数的最小值。如果继续降序,说明又向左走了,这样等到下次向右走得时候也要再次更新最小值。
10 / \ 5 12 / \2 6
如这个例子,我们在10的位置是没有最小值限定的,然后降序走到5,依然没有最小值,降序走到2,依然没有,然后开始升序了,遇到6,这时候之后的数字一定大于2,同时也大于5,所以最小值更新为之前遍历过的,且比当前数稍微小一点的那个数。这里我们可以用一个栈来暂存之前的路径,所以升序时就是将栈中元素不断pop出来直到栈顶大于当前数,而最小值就是最后一个pop出来的数,最后再把该数push进去。对于降序的时候,直接向里面push就行了。这样,序列无效的条件就是违反了这个最小值的限定。
代码
public class Solution { public boolean verifyPreorder(int[] preorder) { Stack<Integer> stk = new Stack<Integer>(); // 初始化最小值为最小整数 int min = Integer.MIN_VALUE; for(int num : preorder){// 违反最小值限定则是无效的if(num < min) return false;// 将路径中所有小于当前的数pop出来并更新最小值while(!stk.isEmpty() && num > stk.peek()){ min = stk.pop();}// 将当前值push进去stk.push(num); } return true; }}
指针模拟栈法
复杂度
时间 O(N) 空间 O(N)
思路
10 / \ 5 12 / \2 6
同样是看这个例子,我们序列是[10, 5, 2, 6, 12]
,如果用栈的话,遍历序列到第n个数时,栈中的情况是这样的:
1 | 102 | 10 53 | 10 5 24 | 10 65 | 12
可见我们栈的大小是不会超过我们当前遍历的数的位置的,所以我们大可以用该序列的之前遍历过的部分来当做我们的栈。这里用一个i指针标记栈顶。
注意
这里栈顶指针应初始化为-1,这样栈第一个元素加入时,i++
后不会超界
代码
public class Solution { public boolean verifyPreorder(int[] preorder) { // 用i标记栈顶 int i = -1, min = Integer.MIN_VALUE; for(int num : preorder){if(num < min) return false;// 同样的解法,但是复用了数组作为栈,每pop一次相当于i--while(i >= 0 && num > preorder[i]){ min = preorder[i--];}// push相当于i++preorder[++i] = num; } return true; }}
后续 Follow Up
Q:如何验证中序序列?
A:中序序列是有序的,只要验证其是否升序的就行了。
Q:如何验证后序序列?
A:后序序列的顺序是left - right - root
,而先序的顺序是root - left - right
。我们同样可以用本题的方法解,不过是从数组的后面向前面遍历,因为root在后面了。而且因为从后往前看是先遇到right再遇到left,所以我们要记录的是限定的最大值,而不再是最小值,栈pop的条件也变成pop所有比当前数大得数。栈的增长方向也是从高向低了。