[LeetCode] 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?
這道題讓給了我們一個一維陣列,讓我們驗證其是否為一個二叉搜尋樹的先序遍歷出的順序,我們都知道二叉搜尋樹的性質是左<根<右,如果用中序遍歷得到的結果就是有序陣列,而先序遍歷的結果就不是有序陣列了,但是難道一點規律都沒有了嗎,其實規律還是有的,根據二叉搜尋樹的性質,當前節點的值一定大於其左子樹中任何一個節點值,而且其右子樹中的任何一個節點值都不能小於當前節點值,那麼我們可以用這個性質來驗證,舉個例子,比如下面這棵二叉搜尋樹:
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); } };
類似題目:
參考資料: