272. Closest Binary Search Tree Value II

这篇博客讨论了如何在二叉搜索树中高效地找到与给定目标值最接近的k个数值。介绍了三种方法:暴力遍历、深度优先搜索和搜索树优化策略。每种方法都分析了其时间复杂度和空间复杂度,其中优化的搜索树方法在平衡树中可以达到更快的查找速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

272. Closest Binary Search Tree Value II

Description

Given the root of a binary search tree, a target value, and an integer k, return the k values in the BST that are closest to the target. You may return the answer in any order.

You are guaranteed to have only one unique set of k values in the BST that are closest to the target.

Idea

题目要求是在二叉搜索树中找到与target最接近的k个值。

最简单的做法:
直接inorder traversal得到整个树的list, 并在此list中找到第一个>=target的值,以此值为中心点向两边寻找最接近target的值。
该做法也可以改进成为一个dfs function: 把res作为parameter传进inorder traversal的function中, 并且res中只保留k个离target最近的数。res可以用deque实现。这样就可以当新遇到的数比res[0]离target近时,以O(1)的时间pop掉res[0]。但无论怎样,时间复杂度为O(n) (n 是 node的个树)空间复杂度为 O(k).

优化的算法:
利用两个stack, 一个用来存target之前的node, 另一个用来存target之后的node。得到这两个stack之后,每次只需要比较stack的最后一个数与target的距离,选最小的一个append到result里即可。
该方法并不需要遍历整个tree。在initialize stack的时候,只需要找到离target最近的前后node和其同枝的node即可。当每次从stack中取出node的时候,再继续把当前pop出node的前或后node加进stack即可。
时间复杂度在最差的情况下依然是O(n) 但当tree比较平衡时可以是O(h + k),因为每一层遍历是,stack中either append右子树的node or append左子树的node 所以对树的搜索是 O(h),O(k)是获取k个结果。
空间复杂度:O(n)

Code

brute-force

时间复杂度为O(n) (n 是 node的个树)空间复杂度为 O(k).

class Solution:
    def closestKValues(self, root: Optional[TreeNode], target: float, k: int) -> List[int]:
        
        value_list = self.inorder(root)
        pos = self.binary_search(value_list, target)
        res = []
        left, right = pos - 1, pos
        for _ in range(k):
            if self.is_left_closer(value_list, target, left, right):
                res.append(value_list[left])
                left -= 1
            else:
                res.append(value_list[right])
                right += 1
        return res

        
    def inorder(self, root):
        if not root:
            return []
        return self.inorder(root.left) + [root.val] + self.inorder(root.right)
    
    def binary_search(self, input_list, target): # find the first value >= target
        
        start, end = 0, len(input_list) - 1
        
        while start < end - 1:
            mid = (start + end) // 2
            if input_list[mid] < target:
                start = mid
            else:
                end = mid
                                                               
        if input_list[start] >= target:
            return start
        return end
    def is_left_closer(self, value_list, target, left, right):
        if left < 0:
            return False
        if right > len(value_list) - 1:
            return True
        if abs(target - value_list[left]) <= abs(target - value_list[right]):
            return True
        return False

DFS

class Solution:
    def closestKValues(self, root: Optional[TreeNode], target: float, k: int) -> List[int]:
        res = collections.deque([])
        self.inorder(root, res, target, k)
        return res
        
    def inorder(self, root, res, target, k):
        if not root:
            return 
        self.inorder(root.left, res, target, k)
        if len(res) == k:
            if abs(root.val - target) < abs(res[0] - target):
                res.popleft()
            else:
                return 
        res.append(root.val)
        self.inorder(root.right, res, target, k)

search on tree

class Solution:
    def closestKValues(self, root: Optional[TreeNode], target: float, k: int) -> List[int]:
        
        if not root:
            return []
        res, pre_stack, next_stack = [], [], []
        while root:
            if root.val >= target:
                next_stack.append(root)
                root = root.left
            else:
                pre_stack.append(root)
                root = root.right
                
        for _ in range(k):
            next_diff = float('inf') if not next_stack else next_stack[-1].val - target
            pre_diff = float('inf') if not pre_stack else target - pre_stack[-1].val
            
            if next_diff > pre_diff:
                res.append(pre_stack[-1].val)
                self.get_pre(pre_stack)
            else:
                res.append(next_stack[-1].val)
                self.get_next(next_stack)
                
        return res
            
                
    def get_next(self, next_stack):
        curr = next_stack.pop()
        node = curr.right
        while node:
            next_stack.append(node)
            node = node.left
            
    def get_pre(self, pre_stack):
        curr = pre_stack.pop()
        node = curr.left
        while node:
            pre_stack.append(node)
            node = node.right

Notes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值