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.
Consider the following binary search tree:
5 / \ 2 6 / \ 1 3
Example 1:
Input: [5,2,6,1,3] Output: false
Example 2:
Input: [5,2,1,3,6] Output: true
Follow up:
Could you do it using only constant space complexity?
這道題讓給了一個一維數組,讓我們驗證其是否為一個二叉搜索樹的先序遍歷出的順序,二叉搜索樹的性質是左<根<右,如果用中序遍歷得到的結果就是有序數組,而先序遍歷的結果就不是有序數組了,但是難道一點規律都沒有了嗎,其實規律還是有的,根據二叉搜索樹的性質,當前節點的值一定大於其左子樹中任何一個節點值,而且其右子樹中的任何一個節點值都不能小於當前節點值,可以用這個性質來驗證,舉個例子,比如下面這棵二叉搜索樹:
5 / \ 2 6 / \ 1 3
其先序遍歷的結果是 {5, 2, 1, 3, 6},先設一個最小值 low,然后遍歷數組,如果當前值小於這個最小值 low,返回 false,對於根節點,將其壓入棧中,然后往后遍歷,如果遇到的數字比棧頂元素小,說明是其左子樹的點,繼續壓入棧中,直到遇到的數字比棧頂元素大,那么就是右邊的值了,需要找到是哪個節點的右子樹,所以更新 low 值並刪掉棧頂元素,然后繼續和下一個棧頂元素比較,如果還是大於,則繼續更新 low 值和刪掉棧頂,直到棧為空或者當前棧頂元素大於當前值停止,壓入當前值,這樣如果遍歷完整個數組之前都沒有返回 false 的話,最后返回 true 即可,參見代碼如下:
解法一:
class Solution { public: bool verifyPreorder(vector<int>& preorder) { int low = INT_MIN; stack<int> s; for (auto a : preorder) { if (a < low) return false; while (!s.empty() && a > s.top()) { low = s.top(); s.pop(); } s.push(a); } return true; } };
下面這種方法和上面的思路相同,為了使空間復雜度為常量,我們不能使用 stack,所以直接修改 preorder,將 low 值存在 preorder 的特定位置即可,前提是不能影響當前的遍歷,參見代碼如下:
解法二:
class Solution { public: bool verifyPreorder(vector<int>& preorder) { int low = INT_MIN, i = -1; for (auto a : preorder) { if (a < low) return false; while (i >= 0 && a > preorder[i]) { low = preorder[i--]; } preorder[++i] = a; } return true; } };
下面這種方法使用了分治法,跟之前那道驗證二叉搜索樹的題 Validate Binary Search Tree 的思路很類似,在遞歸函數中維護一個下界 lower 和上界 upper,那么當前遍歷到的節點值必須在 (lower, upper) 區間之內,然后在給定的區間內搜第一個大於當前節點值的點,以此為分界,左右兩部分分別調用遞歸函數,注意左半部分的 upper 更新為當前節點值 val,表明左子樹的節點值都必須小於當前節點值,而右半部分的遞歸的 lower 更新為當前節點值 val,表明右子樹的節點值都必須大於當前節點值,如果左右兩部分的返回結果均為真,則整體返回真,參見代碼如下:
解法三:
class Solution { public: bool verifyPreorder(vector<int>& preorder) { return helper(preorder, 0, preorder.size() - 1, INT_MIN, INT_MAX); } bool helper(vector<int>& preorder, int start, int end, int lower, int upper) { if (start > end) return true; int val = preorder[start], i = 0; if (val <= lower || val >= upper) return false; for (i = start + 1; i <= end; ++i) { if (preorder[i] >= val) break; } return helper(preorder, start + 1, i - 1, lower, val) && helper(preorder, i, end, val, upper); } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/255
類似題目:
Binary Tree Preorder Traversal
參考資料:
https://leetcode.com/problems/verify-preorder-sequence-in-binary-search-tree/