[LeetCode] Kth Smallest Element in a BST 二叉搜索树中的第K小的元素
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST's total elements.
Example 1:
Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
Output: 1
Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
Credits:
Special thanks to @ts for adding this problem and creating all test cases.
这又是一道关于二叉搜索树 Binary Search Tree 的题, LeetCode 中关于 BST 的题有 Validate Binary Search Tree, Recover Binary Search Tree, Binary Search Tree Iterator, Unique Binary Search Trees, Unique Binary Search Trees II,Convert Sorted Array to Binary Search Tree 和 Convert Sorted List to Binary Search Tree。那么这道题给的提示是让我们用 BST 的性质来解题,最重要的性质是就是左<根<右,如果用中序遍历所有的节点就会得到一个有序数组。所以解题的关键还是中序遍历啊。关于二叉树的中序遍历可以参见我之前的博客 Binary Tree Inorder Traversal,里面有很多种方法可以用,先来看一种非递归的方法,中序遍历最先遍历到的是最小的结点,只要用一个计数器,每遍历一个结点,计数器自增1,当计数器到达k时,返回当前结点值即可,参见代码如下:
解法一:
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
int cnt = ;
stack<TreeNode*> s;
TreeNode *p = root;
while (p || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
p = s.top(); s.pop();
++cnt;
if (cnt == k) return p->val;
p = p->right;
}
return ;
}
};
当然,此题我们也可以用递归来解,还是利用中序遍历来解,代码如下:
解法二:
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
return kthSmallestDFS(root, k);
}
int kthSmallestDFS(TreeNode* root, int &k) {
if (!root) return -;
int val = kthSmallestDFS(root->left, k);
if (k == ) return val;
if (--k == ) return root->val;
return kthSmallestDFS(root->right, k);
}
};
再来看一种分治法的思路,由于 BST 的性质,可以快速定位出第k小的元素是在左子树还是右子树,首先计算出左子树的结点个数总和 cnt,如果k小于等于左子树结点总和 cnt,说明第k小的元素在左子树中,直接对左子结点调用递归即可。如果k大于 cnt+1,说明目标值在右子树中,对右子结点调用递归函数,注意此时的k应为 k-cnt-1,应为已经减少了 cnt+1 个结点。如果k正好等于 cnt+1,说明当前结点即为所求,返回当前结点值即可,参见代码如下:
解法三:
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
int cnt = count(root->left);
if (k <= cnt) {
return kthSmallest(root->left, k);
} else if (k > cnt + ) {
return kthSmallest(root->right, k - cnt - );
}
return root->val;
}
int count(TreeNode* node) {
if (!node) return ;
return + count(node->left) + count(node->right);
}
};
这道题的 Follow up 中说假设该 BST 被修改的很频繁,而且查找第k小元素的操作也很频繁,问我们如何优化。其实最好的方法还是像上面的解法那样利用分治法来快速定位目标所在的位置,但是每个递归都遍历左子树所有结点来计算个数的操作并不高效,所以应该修改原树结点的结构,使其保存包括当前结点和其左右子树所有结点的个数,这样就可以快速得到任何左子树结点总数来快速定位目标值了。定义了新结点结构体,然后就要生成新树,还是用递归的方法生成新树,注意生成的结点的 count 值要累加其左右子结点的 count 值。然后在求第k小元素的函数中,先生成新的树,然后调用递归函数。在递归函数中,不能直接访问左子结点的 count 值,因为左子节结点不一定存在,所以要先判断,如果左子结点存在的话,那么跟上面解法的操作相同。如果不存在的话,当此时k为1的时候,直接返回当前结点值,否则就对右子结点调用递归函数,k自减1,参见代码如下:
解法四:
// Follow up
class Solution {
public:
struct MyTreeNode {
int val;
int count;
MyTreeNode *left;
MyTreeNode *right;
MyTreeNode(int x) : val(x), count(), left(NULL), right(NULL) {}
}; MyTreeNode* build(TreeNode* root) {
if (!root) return NULL;
MyTreeNode *node = new MyTreeNode(root->val);
node->left = build(root->left);
node->right = build(root->right);
if (node->left) node->count += node->left->count;
if (node->right) node->count += node->right->count;
return node;
} int kthSmallest(TreeNode* root, int k) {
MyTreeNode *node = build(root);
return helper(node, k);
} int helper(MyTreeNode* node, int k) {
if (node->left) {
int cnt = node->left->count;
if (k <= cnt) {
return helper(node->left, k);
} else if (k > cnt + ) {
return helper(node->right, k - - cnt);
}
return node->val;
} else {
if (k == ) return node->val;
return helper(node->right, k - );
}
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/230
类似题目:
Second Minimum Node In a Binary Tree
参考资料:
https://leetcode.com/problems/kth-smallest-element-in-a-bst/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Kth Smallest Element in a BST 二叉搜索树中的第K小的元素的更多相关文章
- [LeetCode] 230. Kth Smallest Element in a BST 二叉搜索树中的第K小的元素
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...
- LeetCode 230 Kth Smallest Element in a BST 二叉搜索树中的第K个元素
1.非递归解法 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * ...
- 230 Kth Smallest Element in a BST 二叉搜索树中第K小的元素
给定一个二叉搜索树,编写一个函数kthSmallest来查找其中第k个最小的元素. 注意:你可以假设k总是有效的,1≤ k ≤二叉搜索树元素个数. 进阶:如果经常修改二叉搜索树(插入/删除操作)并且你 ...
- [leetcode] 230. Kth Smallest Element in a BST 找出二叉搜索树中的第k小的元素
题目大意 https://leetcode.com/problems/kth-smallest-element-in-a-bst/description/ 230. Kth Smallest Elem ...
- Leetcode Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...
- [LeetCode] Insert into a Binary Search Tree 二叉搜索树中插入结点
Given the root node of a binary search tree (BST) and a value to be inserted into the tree, insert t ...
- LeetCode Kth Smallest Element in a BST(数据结构)
题意: 寻找一棵BST中的第k小的数. 思路: 递归比较方便. /** * Definition for a binary tree node. * struct TreeNode { * int v ...
- [LeetCode] Inorder Successor in BST 二叉搜索树中的中序后继节点
Given a binary search tree and a node in it, find the in-order successor of that node in the BST. No ...
- [LeetCode] 285. Inorder Successor in BST 二叉搜索树中的中序后继节点
Given a binary search tree and a node in it, find the in-order successor of that node in the BST. Th ...
随机推荐
- Javascript学习笔记1
一.写在前面的话 之前一直没有系统的学习javascript,自己也是小白,很多东西感觉不会,从本篇起,自己会抽出时间来,慢慢学习,好好领会! 深知学习是一个漫长的过程,来不得急躁,不积跬步,无以至千 ...
- Linux发邮件之mail命令
一.mail命令 1.配置 vim /etc/mail.rc 文件尾增加以下内容 set from=1968089885@qq.com smtp="smtp.qq.com" set ...
- TFS2017持续集成构建
TFS2017发布已经有几个月了,经过了几天的部署和尝试,TFS2017的功能变化真是挺大的.特别是在构建方面的变化,在产品的向导中已经声明XAML版本控制器和代理已经弃用了,并建议升级原来13和15 ...
- Bloom Filter:海量数据的HashSet
Bloom Filter一般用于数据的去重计算,近似于HashSet的功能:但是不同于Bitmap(用于精确计算),其为一种估算的数据结构,存在误判(false positive)的情况. 1. 基本 ...
- java占位符应用
(转载自:http://www.cnblogs.com/happyday56/p/3996498.html) String类的format()方法用于创建格式化的字符串以及连接多个字符串对象.熟悉C语 ...
- .Net语言 APP开发平台——Smobiler学习日志:快速实现应用中的图片、声音等文件上传功能
最前面的话:Smobiler是一个在VS环境中使用.Net语言来开发APP的开发平台,也许比Xamarin更方便 样式一 一.目标样式 我们要实现上图中的效果,需要如下的操作: 1.从工具栏上的&qu ...
- Navisworks Api Quantification
Quantification 国外有的叫定量 我们国内一些施工方叫工程量. 通过TakeOff API的开发者有机会获得更多的数据和数据可通过图形用户界面. 1 添加Navisworks的Api ...
- C#开发微信门户及应用(40)--使用微信JSAPI实现微信支付功能
在我前面的几篇博客,有介绍了微信支付.微信红包.企业付款等各种和支付相关的操作,不过上面都是基于微信普通API的封装,本篇随笔继续微信支付这一主题,继续介绍基于微信网页JSAPI的方式发起的微信支付功 ...
- wnmp环境搭建
windows下配置nginx+php环境 刚看到nginx这个词,我很好奇它的读法(engine x),我的直译是“引擎x”,一般引“擎代”表了性能,而“x”大多出现是表示“xtras(额外的效果) ...
- gulp-uglify 与gulp.watch()配合使用时遇到的重复压缩问题
今天学习gulp时候,用到gulp-uglify压缩js模块,遇到的一个问题-当用gulp.watch来监听js文件的变动时出现重复压缩的问题 目录结构如下: gulpfile.js代码如下: var ...