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

Note:

  • Given target value is a floating point.
  • You may assume k is always valid, that is: k≤ total nodes.
  • You are guaranteed to have only one unique set of k values in the BST that are closest to the target.

Example:

Input: root = [4,2,5,1,3], target = 3.714286, and k = 2

    4
/ \
2 5
/ \
1 3 Output: [4,3]

Follow up:
Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)?

这道题是之前那道 Closest Binary Search Tree Value 的拓展,那道题只让找出离目标值最近的一个节点值,而这道题让找出离目标值最近的k个节点值,难度瞬间增加了不少,博主最先想到的方法是用中序遍历将所有节点值存入到一个一维数组中,由于二分搜索树的性质,这个一维数组是有序的,然后再在有序数组中需要和目标值最近的k个值就简单的多,参见代码如下:

解法一:

class Solution {
public:
vector<int> closestKValues(TreeNode* root, double target, int k) {
vector<int> res, v;
inorder(root, v);
int idx = ;
double diff = numeric_limits<double>::max();
for (int i = ; i < v.size(); ++i) {
if (diff >= abs(target - v[i])) {
diff = abs(target - v[i]);
idx = i;
}
}
int left = idx - , right = idx + ;
for (int i = ; i < k; ++i) {
res.push_back(v[idx]);
if (left >= && right < v.size()) {
if (abs(v[left] - target) > abs(v[right] - target)) {
idx = right;
++right;
} else {
idx = left;
--left;
}
} else if (left >= ) {
idx = left;
--left;
} else if (right < v.size()) {
idx = right;
++right;
}
}
return res;
}
void inorder(TreeNode *root, vector<int> &v) {
if (!root) return;
inorder(root->left, v);
v.push_back(root->val);
inorder(root->right, v);
}
};

还有一种解法是直接在中序遍历的过程中完成比较,当遍历到一个节点时,如果此时结果数组不到k个,直接将此节点值加入结果 res 中,如果该节点值和目标值的差值的绝对值小于结果 res 的首元素和目标值差值的绝对值,说明当前值更靠近目标值,则将首元素删除,末尾加上当前节点值,反之的话说明当前值比结果 res 中所有的值都更偏离目标值,由于中序遍历的特性,之后的值会更加的遍历,所以此时直接返回最终结果即可,参见代码如下:

解法二:

class Solution {
public:
vector<int> closestKValues(TreeNode* root, double target, int k) {
vector<int> res;
inorder(root, target, k, res);
return res;
}
void inorder(TreeNode *root, double target, int k, vector<int> &res) {
if (!root) return;
inorder(root->left, target, k, res);
if (res.size() < k) res.push_back(root->val);
else if (abs(root->val - target) < abs(res[] - target)) {
res.erase(res.begin());
res.push_back(root->val);
} else return;
inorder(root->right, target, k, res);
}
};

下面这种方法是上面那种方法的迭代写法,原理一模一样,参见代码如下:

解法三:

class Solution {
public:
vector<int> closestKValues(TreeNode* root, double target, int k) {
vector<int> res;
stack<TreeNode*> s;
TreeNode *p = root;
while (p || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
p = s.top(); s.pop();
if (res.size() < k) res.push_back(p->val);
else if (abs(p->val - target) < abs(res[] - target)) {
res.erase(res.begin());
res.push_back(p->val);
} else break;
p = p->right;
}
return res;
}
};

在来看一种利用最大堆来解题的方法,堆里保存的一个差值 diff 和节点值的 pair,中序遍历二叉树(也可以用其他遍历方法),然后对于每个节点值都计算一下和目标值之差的绝对值,由于最大堆的性质,diff 大的自动拍到最前面,维护k个 pair,如果超过了k个,就把堆前面大的 pair 删掉,最后留下的k个 pair,将 pair 中的节点值取出存入结果 res 中返回即可,参见代码如下:

解法四:

class Solution {
public:
vector<int> closestKValues(TreeNode* root, double target, int k) {
vector<int> res;
priority_queue<pair<double, int>> q;
inorder(root, target, k, q);
while (!q.empty()) {
res.push_back(q.top().second);
q.pop();
}
return res;
}
void inorder(TreeNode *root, double target, int k, priority_queue<pair<double, int>> &q) {
if (!root) return;
inorder(root->left, target, k, q);
q.push({abs(root->val - target), root->val});
if (q.size() > k) q.pop();
inorder(root->right, target, k, q);
}
};

下面的这种方法用了两个栈,pre 和 suc,其中 pre 存小于目标值的数,suc 存大于目标值的数,开始初始化 pre 和 suc 的时候,要分别将最接近目标值的稍小值和稍大值压入 pre 和 suc,然后循环k次,每次比较 pre 和 suc 的栈顶元素,看谁更接近目标值,将其存入结果 res 中,然后更新取出元素的栈,依次类推直至取完k个数返回即可,参见代码如下:

解法五:

class Solution {
public:
vector<int> closestKValues(TreeNode* root, double target, int k) {
vector<int> res;
stack<TreeNode*> pre, suc;
while (root) {
if (root->val <= target) {
pre.push(root);
root = root->right;
} else {
suc.push(root);
root = root->left;
}
}
while (k-- > ) {
if (suc.empty() || !pre.empty() && target - pre.top()->val < suc.top()->val - target) {
res.push_back(pre.top()->val);
getPredecessor(pre);
} else {
res.push_back(suc.top()->val);
getSuccessor(suc);
}
}
return res;
}
void getPredecessor(stack<TreeNode*> &pre) {
TreeNode *t = pre.top(); pre.pop();
if (t->left) {
pre.push(t->left);
while (pre.top()->right) pre.push(pre.top()->right);
}
}
void getSuccessor(stack<TreeNode*> &suc) {
TreeNode *t = suc.top(); suc.pop();
if (t->right) {
suc.push(t->right);
while (suc.top()->left) suc.push(suc.top()->left);
}
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/272

类似题目:

Closest Binary Search Tree Value

Binary Tree Inorder Traversal

参考资料:

https://leetcode.com/problems/closest-binary-search-tree-value-ii/

https://leetcode.com/problems/closest-binary-search-tree-value-ii/discuss/70515/Java-in-order-traversal-1ms-solution

https://leetcode.com/problems/closest-binary-search-tree-value-ii/discuss/70511/AC-clean-Java-solution-using-two-stacks

https://leetcode.com/problems/closest-binary-search-tree-value-ii/discuss/70549/Clear-Java-Solution-with-one-stack-one-linkedlist

https://leetcode.com/problems/closest-binary-search-tree-value-ii/discuss/70503/O(logN)-Java-Solution-with-two-stacks-following-hint

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Closest Binary Search Tree Value II 最近的二分搜索树的值之二的更多相关文章

  1. [LeetCode] 272. Closest Binary Search Tree Value II 最近的二分搜索树的值之二

    Given a non-empty binary search tree and a target value, find k values in the BST that are closest t ...

  2. LeetCode Closest Binary Search Tree Value II

    原题链接在这里:https://leetcode.com/problems/closest-binary-search-tree-value-ii/ 题目: Given a non-empty bin ...

  3. [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 t ...

  4. LeetCode Closest Binary Search Tree Value

    原题链接在这里:https://leetcode.com/problems/closest-binary-search-tree-value/ Given a non-empty binary sea ...

  5. [Locked] Closest Binary Search Tree Value & Closest Binary Search Tree Value II

    Closest Binary Search Tree Value  Given a non-empty binary search tree and a target value, find the ...

  6. [LeetCode] 272. Closest Binary Search Tree Value II 最近的二叉搜索树的值 II

    Given a non-empty binary search tree and a target value, find k values in the BST that are closest t ...

  7. 272. Closest Binary Search Tree Value II

    题目: Given a non-empty binary search tree and a target value, find k values in the BST that are close ...

  8. [LeetCode#272] Closest Binary Search Tree Value II

    Problem: Given a non-empty binary search tree and a target value, find k values in the BST that are ...

  9. [leetcode]272. Closest Binary Search Tree Value II二叉搜索树中最近的值2

    Given a non-empty binary search tree and a target value, find k values in the BST that are closest t ...

随机推荐

  1. 数据结构笔记--栈的总结及java数组实现简单栈结构

    杂谈"栈"结构: 栈(Stack)是一种插入删除操作都只能在一个位置上进表,这个位置位于表的末端,叫做栈顶(Top). 对栈的基本操作有push和pop,表示进栈和出栈.也就相当于 ...

  2. 修改版: 小伙,多线程(GCD)看我就够了,骗你没好处!

    多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术.具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能.具有这种能力的系 ...

  3. SQL Server SQL性能优化之--通过拆分SQL提高执行效率,以及性能高低背后的原因

    复杂SQL拆分优化 拆分SQL是性能优化一种非常有效的方法之一, 具体就是将复杂的SQL按照一定的逻辑逐步分解成简单的SQL,借助临时表,最后执行一个等价的逻辑,已达到高效执行的目的 一直想写一遍通过 ...

  4. Apache Spark简单介绍、安装及使用

    Apache Spark简介 Apache Spark是一个高速的通用型计算引擎,用来实现分布式的大规模数据的处理任务. 分布式的处理方式可以使以前单台计算机面对大规模数据时处理不了的情况成为可能. ...

  5. 「译」JUnit 5 系列:架构体系

    原文地址:http://blog.codefx.org/design/architecture/junit-5-architecture/ 原文日期:29, Mar, 2016 译文首发:Linesh ...

  6. JQuery的核心的一些方法[扒来的]

    JQuery的核心的一些方法 each(callback) '就像循环 $("Element").length; ‘元素的个数,是个属性 $("Element" ...

  7. Lightbox改造——支持滚轮缩放

    在做文章类型的web页时,经常会遇到要点开看大图的需求,LightBox2则是在众多产品中比较优秀的一款Jquery插件.配置就不细说了,今天我主要要分享的是:如何在点开大图后,可以通过鼠标滚轮来缩放 ...

  8. 【设计模式】单例模式 c++实现

    单例模式一般应用在整个应用中只会存在一个对象.比如应用类,游戏场景类,工具类等. 实现方式: 头文件 singleton.h: #ifndef _SINGLETON_H_ #define _SINGL ...

  9. 怎样才能自学好Java?

    经常有初学Java的同学问:怎么样才能学好Java?自学Java难吗? 我认为自学Java并不难.相对于其他语言来说,因为Java95年才出来,所以相对比较新,旧的语言中一些不合适的东西在Java里面 ...

  10. jsPanel插件Option总结

    jsPanel插件Option总结 学习jsPanel之余对相关的选项进行了总结,便于参考. # 选项名称 类别 简要说明 1 autoclose configuration 设置一个时间在毫秒后,面 ...