1. 程式人生 > >[LeetCode] Closest Binary Search Tree Value 最近的二分搜尋樹的值

[LeetCode] Closest Binary Search Tree Value 最近的二分搜尋樹的值

Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.

Note:

  • Given target value is a floating point.
  • You are guaranteed to have only one unique value in the BST that is closest to the target.

這道題讓我們找一個二分搜尋數的跟給定值最接近的一個節點值,由於是二分搜尋樹,所以我最先想到用中序遍歷來做,一個一個的比較,維護一個最小值,不停的更新,實際上這種方法並沒有提高效率,用其他的遍歷方法也可以,參見程式碼如下:

解法一:

class Solution {
public:
    int closestValue(TreeNode* root, double target) {
        double d = numeric_limits<double>::max();
        int res = 0;
        stack<TreeNode*> s;
        TreeNode *p = root;
        while (p || !s.empty()) {
            while (p) {
                s.push(p);
                p 
= p->left; } p = s.top(); s.pop(); if (d >= abs(target - p->val)) { d = abs(target - p->val); res = p->val; } p = p->right; } return res; } };

實際我們可以利用二分搜尋樹的特點(左<根<右)來快速定位,由於根節點是中間值,我們在往下遍歷時,我們根據目標值和根節點的值大小關係來比較,如果目標值小於節點值,則我們應該找更小的值,於是我們到左子樹去找,反之我們去右子樹找,參見程式碼如下:

解法二:

class Solution {
public:
    int closestValue(TreeNode* root, double target) {
        int res = root->val;
        while (root) {
            if (abs(res - target) >= abs(root->val - target)) {
                res = root->val;
            }
            root = target < root->val ? root->left : root->right;
        }
        return res;
    }
};

以上兩種方法都是迭代的方法,下面我們來看遞迴的寫法,下面這種遞迴的寫法和上面迭代的方法思路相同,都是根據二分搜尋樹的性質來優化查詢,但是遞迴的寫法用的是回溯法,先遍歷到葉節點,然後一層一層的往回走,把最小值一層一層的運回來,參見程式碼如下:

解法三:

class Solution {
public:
    int closestValue(TreeNode* root, double target) {
        int a = root->val;
        TreeNode *t = target < a ? root->left : root->right;
        if (!t) return a;
        int b = closestValue(t, target);
        return abs(a - target) < abs(b - target) ? a : b;
    }
};

再來看另一種遞迴的寫法,思路和上面的都相同,寫法上略有不同,用if來分情況,參見程式碼如下:

解法三:

class Solution {
public:
    int closestValue(TreeNode* root, double target) {
        int res = root->val;
        if (target < root->val && root->left) {
            int l = closestValue(root->left, target);
            if (abs(res - target) >= abs(l - target)) res = l;
        } else if (target > root->val && root->right) {
            int r = closestValue(root->right, target);
            if (abs(res - target) >= abs(r - target)) res = r;
        }
        return res;
    }
};

最後來看一種分治法的寫法,這種方法相當於解法一的遞迴寫法,並沒有利用到二分搜尋樹的性質來優化搜尋,參見程式碼如下:

解法四:

class Solution {
public:
    int closestValue(TreeNode* root, double target) {
        double diff = numeric_limits<double>::max();
        int res = 0;
        helper(root, target, diff, res);
        return res;
    }
    void helper(TreeNode *root, double target, double &diff, int &res) {
        if (!root) return;
        if (diff >= abs(root->val - target)) {
            diff = abs(root->val - target);
            res = root->val;
        }
        helper(root->left, target, diff, res);
        helper(root->right, target, diff, res);
    }
};

參考資料: