1. 程式人生 > >Leetcode 98 Validate Binary Search Tree 驗證二叉查詢樹

Leetcode 98 Validate Binary Search Tree 驗證二叉查詢樹

題目描述

Given a binary tree, determine if it is a valid binary search tree (BST).
給出一個二叉樹,判斷其是否是合法的二叉查詢樹。

解題思路

首先,我們來看二叉查詢樹的定義:

  1. 根節點的左子樹上所有節點的值都小於根節點的值
  2. 根節點的右子樹上所有節點的值都大於根節點的值
  3. 左右子樹分別都是二叉查詢樹

接下來,我們就可以很容易的寫出一個遞迴方法來實現上述演算法。

解法一

此種方法緊扣定義,我們假設有兩個方法noGreater和noLess分別判定左右子樹上左右節點的值分別不小於、不大於根節點的值,然後遞迴判斷左右子樹是否為二叉查詢樹。

演算法描述

  1. 如果root為空返回true;
  2. 判斷左子樹上所有節點的值都小於根節點的值和右子樹上所有節點的值都大於根節點的值是否同時成立,如果成立,則遞迴判斷左右子樹是二叉查詢樹是否同時成立,否則返回false。

分析

演算法時間複雜度O(n^2),空間複雜度O(c)

程式碼

/**
 * 驗證二叉樹是否為合法的二插查詢樹
 */
bool isValidBST(struct TreeNode *root) {
    bool noGreater(struct TreeNode *, int);
    bool noLess(struct TreeNode *, int);
    // 空,返回true
if (root == NULL) return true; // 判斷: // 1.左子樹上所有節點的值都小於根節點的值 // 2.右子樹上所有節點的值都大於根節點的值 if (noGreater(root->left, root->val) && noLess(root->right, root->val)) // 如果同時成立則,遞迴判斷左右子樹是二叉查詢樹是否同時成立 return isValidBST(root->left) && isValidBST(root->right); else
// 如果不同時成立,返回false return false; } /** * 判斷以root為根節點的二叉樹上的所有節點的值是否都大於val */ bool noLess(struct TreeNode *root, int val) { // 空,返回true if (root == NULL) return true; // 如果根節點的值不大於val,返回false if (root->val <= val) return false; // 遞迴判定root的左右子樹上的所有節點值是否都大於val return noLess(root->left, val) && noLess(root->right, val); } /** * 判斷以root為根節點的二叉樹上的所有節點的值是否都小於val */ bool noGreater(struct TreeNode *root, int val) { // 空,返回true if (root == NULL) return true; // 如果根節點的值不小於val,返回false if (root->val >= val) return false; // 遞迴判定root的左右子樹上的所有節點值是否都小於val return noGreater(root->left, val) && noGreater(root->right, val); }

執行情況

Status:Accept
Time:12ms

解法二

那我們有沒有一種方法只遍歷二叉樹一次呢?

有!

我們來觀察二叉查詢樹,可以發現二叉查詢樹的一個特點,那就二叉查詢樹中序遍歷可以得到一個遞增的序列,現在事情變得簡單起來,我們只需中序遍歷二叉樹,判斷其序列是否遞增即可。

演算法描述

中序遍歷二叉樹,判斷結果序列是否遞增

分析

中序遍歷只遍歷二叉樹一次,演算法時間複雜度O(n),空間複雜度O(c)

程式碼

/**
 * 驗證二叉樹是否為合法的二插查詢樹
 */
bool isValidBST(struct TreeNode *root) {
    bool inorderTraversal(struct TreeNode *, int *, bool *);

    int last;           // 用來儲存中序遍歷時的上一個點
    bool isFirst = true;// 用來表示是否為中序遍歷獲取到的第一個點

    //中序遍歷二叉樹,看其是否遞增
    return inorderTraversal(root, &last, &isFirst);
}

/**
 * 中序遍歷二叉樹,看其是否遞增
 */
bool inorderTraversal(struct TreeNode *root, int *last, bool *isFirst) {
    // 空,返回true 
    if (root == NULL)
        return true;

    /* 中序遍歷左子樹 */
    if (root->left != NULL) // 這個判斷語句可以沒有
        // 如果左子樹中序遍歷序列不遞增,返回false
        if (!inorderTraversal(root->left, last, isFirst)) 
            return false;

    /* 遍歷當前節點 */
    if (*isFirst) { // 如果當前節點是中序遍歷獲得的第一個節點
        *isFirst = false; // 修改標誌位
        *last = root->val;// 更新中序遍歷過程中上一個點的值
    } else { // 如果當前節點不是中序遍歷獲得的第一個節點
        if (*last >= root->val) // 判斷當前節點是否大於遍歷的上一個點
            return false; // 當前節點不大於上一個點,返回false
        else // 當前節點大於上一個點,更新中序遍歷過程中上一個點的值
            *last = root->val;
    }

    /* 中序遍歷左子樹 */
    if (root->right != NULL) // 這個判斷語句可以沒有
        // 如果右子樹中序遍歷序列不遞增,返回false
        if(!inorderTraversal(root->right, last, isFirst))
            return false;

    // 執行至此,說明中序遍歷序列遞增,返回true
    return true;
}

執行情況

Status:Accept
Time:8ms

// 個人學習記錄,若有錯誤請指正,大神勿噴
// [email protected]
// 2015-05-27