1. 程式人生 > >[LeetCode] Verify Preorder Sequence in Binary Search Tree 驗證二叉搜尋樹的先序序列

[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);
    }
};

類似題目:

參考資料: