目录
刷题日期:上午5:18 2021年5月17日星期一
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 54. 二叉搜索树的第k大节点
难度简单159
给定一棵二叉搜索树,请找出其中第k大的节点。
示例 1:
输入: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
输出: 4
示例 2:
输入: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
输出: 4
限制:
1 ≤ k ≤ 二叉搜索树元素个数
题目分析
二叉搜索树的特点就是左子树<根节点<右子树。第k大遍是排序后的l-k
位。
树的话不遍历也不知道到底有多少个元素,所以感觉至少还是得过一遍。
如果只是单纯的找最大和最小,那么一直找左子树和右子树即可。设计数组存放所有叶子节点,然后排序,然后取出相应位的结果。
初始解答:
二叉树的遍历记得可以用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 kthLargest(TreeNode root, int k) {
if(root == null || k == 0) return 0;
return mfs(root, k).val;
}
public TreeNode mfs(TreeNode root, int k) {
TreeNode cur = new TreeNode();
cur = null;
if(root.left != null) cur = mfs(root.left, k);
if(cur == null) {
if(k == 1) cur = root;
k--;
}
if(cur == null && root.right != null) cur = mfs(root.right, k);
return cur;
}
}
已完成 执行用时:0 ms
输入 [3,1,4,null,2] 1
输出 1
差别 预期结果 4
看到方法二意识到问的第k大应该是右根左,修改后能跑通示例但是还是卡住了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int kthLargest(TreeNode root, int k) {
if(root == null || k == 0) return 0;
return mfs(root, k).val;
}
public TreeNode mfs(TreeNode root, int k) {
TreeNode cur = new TreeNode();
cur = null;
if(root.right != null) cur = mfs(root.right, k);
if(cur == null) {
if(k == 1) cur = root;
k--;
}
if(cur == null && root.left != null) cur = mfs(root.left, k);
return cur;
}
}
添加备注 输入: [5,3,6,2,4,null,null,1] 3
输出: 2
预期结果: 4
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private int ans = 0, cnt = 0;
public int kthLargest(TreeNode root, int k) {
mfs(root, k);
return ans;
}
private void mfs(TreeNode root, int k) {
if(root == null) return ;
mfs(root.right, k); //右
if(++cnt == k) { //每进一次都更接近k
ans = root.val; //根
}
mfs(root.left, k); //左
}
}
执行结果: 通过
显示详情 添加备注
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:37.9 MB, 在所有 Java 提交中击败了97.69%的用户
K神的解法,this之前没怎么接触过
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
int ans, k;
public int kthLargest(TreeNode root, int k) {
this.k = k; //
mfs(root);
return ans;
}
void mfs(TreeNode root) {
if(root == null) return ;
mfs(root.right); //右
if(--k == 0) { //每进一次都更接近k
ans = root.val; //根
// return;
}
mfs(root.left); //左
}
}
执行结果: 通过
显示详情 添加备注
执行用时:1 ms, 在所有 Java 提交中击败了40.41%的用户
内存消耗:38.2 MB, 在所有 Java 提交中击败了72.19%的用户
学习他人:
方法一:
(编辑过)2020-02-19
作为一个普通人,我来分析下这题。
- 假设,你花了点时间,练习了二叉树的三种遍历方式: a. 前序遍历 b. 中序遍历 c. 后续遍历
- 你也学习了二叉搜索树,深入研究了二叉树搜索树的特性,并且深刻知道二叉搜索树的一个特性:通过中序遍历所得到的序列,就是有序的。
好,有了以上两点知识,我认为你必须能想到(如果想不到,以上两点知识肯定没有学扎实):中序遍历二叉搜索树,遍历的同时,把遍历到的节点存到一个可变数组里(Java的话,可以用ArrayList)。 思路转化为代码,如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int kthLargest(TreeNode root, int k) {
// clarification: root == null? k <= 1?
List<Integer> list = new ArrayList<>();
helper(root, list);
return list.get(list.size() - k);
}
private void helper(TreeNode root, List<Integer> list) {
if (root == null) return;
if (root.left != null) helper(root.left, list);
list.add(root.val);
if (root.right != null) helper(root.right, list);
}
}
到这里,这题,我觉得已经离最优解很近了。作为一个学习了算法的人,你一定会想:上面的算法空间复杂度是O(n),可不可以优化?
深入再思考下,其实,当遍历到了第K大数的时候,就可以停止遍历了,同时,把遍历到节点对应的数保存下来即可。
想到这里,一定能写出下面的代码:
class Solution {
int n = 0;
int res = 0;
public int kthLargest(TreeNode root, int k) {
n = k;
helper(root);
return res;
}
public void helper(TreeNode root){
if(root.right != null && n>0 ) helper(root.right);
n--;
if(n==0){
res = root.val;
return;
}
if(root.left != null && n>0 ) helper(root.left);
}
}
这题,到这里,我想,已经完美了!最后,再次强调下,我就是个普通人,只能使用普通人的思维方式。
方法二:
Roni (编辑过)2020-02-14 【Java】【递归】
- 注意是第K大,所以右根左;第K小才是左根右
class Solution {
private int ans = 0, cnt = 0;
public int kthLargest(TreeNode root, int k) {
dfs(root, k);
return ans;
}
private void dfs(TreeNode root, int k) {
if(root == null) return ;
dfs(root.right, k);
if(++cnt == k) {
ans = root.val;
}
dfs(root.left, k);
}
}
方法三:
coders-47L1 2021-05-04
方法一:中序遍历(由小到大遍历),都加数组算索引即可 方法二:由大到小的方式遍历,到第k个节点即可
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init(_ val: Int) {
* self.val = val
* self.left = nil
* self.right = nil
* }
* }
*/
class Solution {
// /// 法一:中序遍历
// func kthLargest(_ root: TreeNode?, _ k: Int) -> Int {
// var array: [Int] = []
// func _traverse(_ root: TreeNode?) {
// guard let root = root else { return }
// _traverse(root.left)
// array.append(root.val)
// _traverse(root.right)
// }
// _traverse(root)
// let index = array.count - k
// return k > 0 ? array[index] : 0
// }
/// 法二:搜索树 右子树永远大于当前节点,右 -》 中 -》 的方式遍历即为从大到小的排序,按照这种方式遍历到第k个节点即可
func kthLargest(_ root: TreeNode?, _ k: Int) -> Int {
var count: Int = 0
var result: Int = 0
func _traverse(_ root: TreeNode?) {
guard let root = root else {
return
}
_traverse(root.right)
count += 1
if count == k {
result = root.val
return
}
_traverse(root.left)
}
_traverse(root)
return result
}
}
方法四:
K神 本文解法基于此性质:二叉搜索树的中序遍历为 递增序列 。
根据以上性质,易得二叉搜索树的 中序遍历倒序 为 递减序列 。
因此,求 “二叉搜索树第 k 大的节点” 可转化为求 “此树的中序遍历倒序的第 k 个节点”。
作者:jyd
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/solution/mian-shi-ti-54-er-cha-sou-suo-shu-de-di-k-da-jie-d/
来源:力扣(LeetCode)
class Solution {
int res, k;
public int kthLargest(TreeNode root, int k) {
this.k = k;
dfs(root);
return res;
}
void dfs(TreeNode root) {
if(root == null) return;
dfs(root.right);
if(k == 0) return;
if(--k == 0) res = root.val;
dfs(root.left);
}
}
完美暴力 2021-02-04
@莫非 综合以下回复
class Solution {
int res, k;
public int kthLargest(TreeNode root, int k) {
this.k = k;
dfs(root);
return res;
}
void dfs(TreeNode root) {
if(root == null) return;
dfs(root.right);
if(--k <= 0)
{
res = root.val;
return;
}
dfs(root.left);
}
}
总结
以上就是本题的内容和学习过程了,方法一的同学所讲的基础,还是欠缺,继续努力吧。
欢迎讨论,共同进步。