我遇到了以下leetcode问题,我对一些人用来解决问题的方法提出了疑问。问题是: 给定非空二进制搜索树和目标值,在BST中找到最接近目标的k值。
注意: 给定目标值是一个浮点。
您可以假设k始终有效,即:k≤总节点数。
保证BST中只有一组唯一的k值最接近目标。
所以,有些人做的是他们按顺序进行遍历,同时保持最近元素的k大小队列。在顺序遍历期间,如果找到的元素比队列中的第一个节点更接近目标,则会从队列中删除第一个节点并添加当前值。我的问题是,他们为什么要与队列中的第一个元素进行比较?这是我所指的一些代码: https://leetcode.com/discuss/94472/inorder-one-linkedlist-java-solution-beat-85%25
答案 0 :(得分:4)
有序遍历将首先找到小于或等于目标的所有元素。随着它接近,新的,越来越近的元素将按排序顺序添加到列表的尾部。在达到k长度后,在尾部添加一个新的close元素需要删除一个更远的元素。最远的是头部,所以它会删除它。
搜索通过目标后,它开始看到距离它更远的元素。每个问题都考虑的问题是它是否比列表中已有的更接近目标。假设k = 5,列表如下所示:
a <= b <= c <= d <= e (<= x?)
^
Target value somewhere between c and d
搜索刚刚发现了下一个值x >= e
。只有两种可能性:
x
比a
更接近目标。在这种情况下,我们要删除a
并在尾部添加x
。
x
离目标的距离比a
更远。在这种情况下,我们单独列出清单。此外,我们可以确定每个进一步的有序元素将远离目标,因此可以缩短搜索范围。
令人高兴的是,在达到目标之前,在完成目标之后进行此选择所需的测试总是得到满足,因此在两种情况下相同的代码都足够了。
这是一个优雅的解决方案,但它具有n
元素树的O(n)运行时。
更复杂但渐近更快的解决方案依赖于树迭代器。可以构建可以在O(h)时间初始化的迭代器,以从h
是树的高度的任何元素开始。在目标上初始化其中两个,然后向左移动一个,向右移动另一个,始终选择最接近目标的移动到下一个。找到k
个元素时停止。推进这些迭代器与按顺序遍历的每个步骤具有相同的时间复杂度:摊销的常量时间。所以整个算法是O(h + k)。如果树是平衡的,那么这是O(log n + k),这在k << n
时要好得多。
答案 1 :(得分:1)
据推测,队列中的第一个节点离队列中元素的目标最远,如果找到比它更近的东西,队列只需要改变。