题意描述:
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
说明:
你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。
进阶:
如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数?
示例:
示例一:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 1
示例二:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 3
解题思路:
Alice🦄: 又是二叉树哦 ?
Bob 🐘:可以直接暴力做呀,前面不是做过一道 求 数组的 第 k 小的数嘛。可以先遍历二叉树,把结果存在数组中,然后再排序,再得到 第 k 小的数。
Alice🦄: 你这是把一个新的问题转换成一个已经解决过的问题对吗 ?不过这样的话二叉搜索树本身的信息 岂不是没有用到吗 ?
Bob🐘: 是啊,所以应该有更简洁的办法去 寻找 二叉搜索树 的第 k 个最小值。
Alice🦄: 二叉搜索树的性质是 左子树的所有值都比 根节点 小,右子树的所有值都比根节点大。然后还有,
Bob🐘: 如果是 找二叉搜索树的最小值,可以找到最深的 那棵左子树 的叶节点就是答案。可是怎么找到第 k 小的值呢 ? 能不能遍历完二叉搜索树之后直接得到一个有序的数组呢 ?
Alice🦄: 有了 (o゜▽゜)o☆,二叉树的前序遍历, 只要在递归的时候先访问二叉搜索树的左子树,然后根节点,最后访问右子树得到的遍历结果就是有序数组 !!!
Bob🐘: 哇,(✧◡✧)
Alice🦄: 😎
代码:
Python 方法一: 暴力求解,遍历二叉搜索树的所有值,排序,得到第K小的值。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.values = []
self.getAllNodes(root)
self.values.sort()
return self.values[k-1]
def getAllNodes(self, root):
if root == None:
return
else:
self.values.append(root.val)
self.getAllNodes(root.left)
self.getAllNodes(root.right)
Java 方法一:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int kthSmallest(TreeNode root, int k) {
List<Integer> values = new ArrayList();
this.getAllNodes(root, values);
int[] tmp = new int[values.size()];
for(int i=0; i<values.size(); ++i){
tmp[i] = values.get(i);
}
Arrays.sort(tmp);
return tmp[k-1];
}
public void getAllNodes(TreeNode root, List<Integer> values){
if(root == null){
return ;
}else{
values.add(root.val);
this.getAllNodes(root.left, values);
this.getAllNodes(root.right, values);
}
}
}
Python 方法二: 深度优先搜索,就是说遍历二叉树的时候,先左子树,再根节点,再右子树。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.values = []
self.getAllNodes(root)
return self.values[k-1]
def getAllNodes(self, root):
if root == None:
return
else:
self.getAllNodes(root.left)
self.values.append(root.val)
self.getAllNodes(root.right)
Python 方法二: dfs + 优化。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.values = []
self.helper(root, k)
return self.values[k-1]
def helper(self, root, k):
if root == None or len(self.values) == k:
return
else:
self.helper(root.left, k)
self.values.append(root.val)
self.helper(root.right, k)
Python 方法二: 再优化一下空间复杂度。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
self.cnt = 1
self.ans = 0
self.helper(root, k)
return self.ans
def helper(self, root, k):
if root == None or self.cnt > k:
return
else:
self.helper(root.left, k)
if self.cnt == k:
self.ans = root.val
self.cnt += 1
self.helper(root.right, k)
Java 方法二: 深度优先搜索, dfs
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int kthSmallest(TreeNode root, int k) {
List<Integer> values = new ArrayList();
this.getAllNodes(root, values);
return values.get(k-1);
}
public void getAllNodes(TreeNode root, List<Integer> values){
if(root == null){
return ;
}else{
this.getAllNodes(root.left, values);
values.add(root.val);
this.getAllNodes(root.right, values);
}
}
}
Java 方法二: dfs + 优化 (提前终止遍历)。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int kthSmallest(TreeNode root, int k) {
List<Integer> values = new ArrayList();
this.getAllNodes(root, k, values);
return values.get(k-1);
}
public void getAllNodes(TreeNode root, int k, List<Integer> values){
if(root == null || values.size() >= k){
return ;
}else{
this.getAllNodes(root.left, k, values);
values.add(root.val);
this.getAllNodes(root.right, k, values);
}
}
}
Java 方法二: dfs + 时间复杂度优化 + 空间复杂度优化。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int cnt = 0;
int ans = 0;
public int kthSmallest(TreeNode root, int k) {
this.helper(root, k);
return this.ans;
}
public void helper(TreeNode root, int k){
if(this.cnt > k || root == null){
return;
}else{
this.helper(root.left, k);
this.cnt += 1;
if(this.cnt == k){
this.ans = root.val;
}
this.helper(root.right, k);
}
}
}
易错点:
- 一些测试样例:
[3,1,4,null,2]
4
[5,3,6,2,4,null,null,1]
3
- 答案:
4
3
总结: