LintCode-900: Closest Binary Search Tree Value

本文介绍了一种高效算法,用于在给定的二叉搜索树中找到最接近特定浮点目标值的整数值。通过递归和迭代方法实现了该算法,并详细解释了每种方法的工作原理。

900 · Closest Binary Search Tree Value
Algorithms
Easy
Accepted Rate
54%

Description
Solution93
Notes
Discuss99+
Leaderboard
Record

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

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.
Example
Example1

Input: root = {5,4,9,2,#,8,10} and target = 6.124780
Output: 5
Explanation:
Binary tree {5,4,9,2,#,8,10}, denote the following structure:
5
/
4 9
/ /
2 8 10
Example2

Input: root = {3,2,4,1} and target = 4.142857
Output: 4
Explanation:
Binary tree {3,2,4,1}, denote the following structure:
3
/
2 4
/
1

我用的方法就是二分递归。当root->val > target时,结果只可能在root和左子树中选,否则就是在root和右子树中选。
注意!虽然pass了,但是还是有漏洞。关键在这一行
if (!root) return INT_MAX;
这里可能不对,因为如果某个节点为空,target是INT_MAX的话,INT_MAX就成了最佳结果了。
代码如下:

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @return: the value in the BST that is closest to the target
    */
    int closestValue(TreeNode * root, double target) {
        if (!root) return INT_MAX; //注意!这里可能不对,因为如果某个节点为空,target是INT_MAX的话,INT_MAX就成了最佳结果了。
        double currGap=abs(root->val-target);

        if (target>root->val) {
            if (root->right) {
                int rightCandidate = closestValue(root->right, target);
                double rightGap=abs(rightCandidate - target);
                if (rightGap<currGap)
                    return rightCandidate;
            }
            return root->val;
    
        } else {
            if (root->left) {
                int leftCandidate = closestValue(root->left, target);
                double leftGap=abs(leftCandidate - target);
                if (leftGap<currGap)
                    return leftCandidate;
            }
            return root->val;
        }
    }
};

注意:下面的解法不对。因为当!root=0时,我们不能返回0。否则如果target是负数而二叉树的节点都是正数的话,这个0就是最佳结果了。但这是不对的,因为二叉树上没有0这个节点。所以下面的递归版上是根据kid是否为空来的,而不是根据root是否为空来的。

int closestValue(TreeNode *root, double target) {
        if (!root) return 0; //这里不对!看看case {2, #, 3} target=-3
        if (!root->left && !root->right) return root->val;
        double rootAbsDiff = abs(root->val - target);
        int closest = 0;
        if (target < root->val) {
            closest = closestValue(root->left, target);
        } else {
            closest = closestValue(root->right, target);
        }
        if (abs(closest - target) > abs(root->val - target)) {
            closest = root->val;
        }
        return closest;
    }
};

另外看到这个链接给出了简明扼要的递归和迭代两种解法,非常好。
http://rainykat.blogspot.com/2017/01/leetcode-270-closest-binary-search-tree.html
递归版:

public class Solution {
    public int closestValue(TreeNode root, double target) {
        // 选出子树的根节点
        TreeNode kid = target < root.val ? root.left : root.right;
        // 如果没有子树,也就是递归到底时,直接返回当前节点值
        if(kid == null) return root.val;  //注意!这一行很牛,包括了root节点没有子节点,和root节点的那个要递归的子节点为空的两种情况!
        // 找出子树中最近的那个节点
        int closest = closestValue(kid, target);
        // 返回根节点和子树最近节点中,更近的那个节点
        return Math.abs(root.val - target) < Math.abs(closest - target) ? root.val : closest;
    }
}

迭代版:
We the node is in tree so traveling the BST and keep a value closet to target

Complexity: O(lgN)

public class Solution {
    public int closestValue(TreeNode root, double target) {
        int closest = root.val;
        while(root!=null){
            //if current root.val is closer, update closest 
            closest = Math.abs(closest-target)<Math.abs(root.val-target)?closest:root.val;
            //do binary search
            root = target<root.val?root.left:root.right;
        }
        return closest;
    }
}

三刷: 前序遍历+二分。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @return: the value in the BST that is closest to the target
     */
    int closestValue(TreeNode *root, double target) {
        closest = root->val;
        helper(root, target);
        return closest;
    }
private:
    int closest = 0;
    void helper(TreeNode *root, double target) {
        if (!root) return;
        //if (!root->left && !root->right) { //注意:这里不能加这行,要不然左右节点只有一个的情况就没有处理。
            if (abs(root->val - target) < abs(closest - target)) closest = root->val;
        //    return;
        //}
        if (target < root->val) helper(root->left, target);
        else helper(root->right, target);
        return;
    }
};

解法3:中序遍历。这个时间复杂度是O(h+k)。h是树的高度,k是返回的点是中序遍历的第几个点。这个算法太慢。不优。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @return: the value in the BST that is closest to the target
     */
    int closestValue(TreeNode *root, double target) {
        stack<TreeNode *> stk;
        int res = root->val;
        while (root || !stk.empty()) {
            while (root) {
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            if (abs(root->val - target) < abs(res - target)) res = root->val;
            root = root->right;
        }
        return res;
    }
};

三刷
还是inorder traversal。注意光这么traversal的时间复杂度是O(n)。没有二分的好。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @return: the value in the BST that is closest to the target
     */
    int closestValue(TreeNode *root, double target) {
        closest = root->val;
        helper(root, target);
        return closest;
    }
private:
    int closest;
    void helper(TreeNode *root, double target) {
        if (!root) return;
        helper(root->left, target);
        if (abs(root->val - target) < abs(closest - target)) {
            closest = root->val;
        }
        helper(root->right, target);
    }
};

解法4:中序遍历+二分。
参考的labuladong的思路。这个方法很好!时间复杂度O(logn)。

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */

class Solution {
public:
    /**
     * @param root: the given BST
     * @param target: the given target
     * @return: the value in the BST that is closest to the target
     */
    int closestValue(TreeNode *root, double target) {
        closest = root->val;
        helper(root, target);
        return closest;
    }
private:
    int closest;
    void helper(TreeNode *root, double target) {
        if (!root) return;

        if (target < root->val) {
            helper(root->left, target);
            if (abs(root->val - target) < abs(closest - target)) {
                closest = root->val;
            }
        } else {
            if (abs(root->val - target) < abs(closest - target)) {
                closest = root->val;
            }
            helper(root->right, target);
        }
    }
};
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值