前言
二叉树的定义就是一个递归结构,一个根节点,衍生出两个孩子节点,依此重复。所以最终的树就是一个根节点root,以及所有的衍生出来的两个节点。
没有孩子节点的就加上null,就能看出这样一个结构。
一、快速解题
用任何一种遍历方式把所有节点值加入到一个list里面,然后做一个降序排序。最后选第k个值。这是快速暴力解题。
1、源码
//剑指offer.54.二叉搜索树的k大节点。
List<Integer> res = new LinkedList<>();
public int kthLargest(TreeNode root, int k) {
//遍历拿到所有节点,然后排个序
preOrder(root);
res.sort((o1, o2) -> o2.compareTo(o1));
return res.get(k - 1);
}
//先序遍历
public void preOrder(TreeNode root) {
if (root == null)
return;
res.add(root.val);
preOrder(root.left);
preOrder(root.right);
}
二、自定义遍历+回溯+剪枝
1、思想
如果你熟悉递归机构,这个题就可以自己定义一个遍历方式,叫做右、根、左。可以理解为中序遍历的逆序。
然后在中间做的操作为计数,并判断该数是否为k,如果为k,就取到这个值,然后剪枝(return)。
2、源码
int k_value = 0;
int k = 0;
//剑指offer.54.二叉搜索树的k大节点,可以注意到这是一个二叉排序树。
public int kthLargest(TreeNode root, int k) {
//遍历拿到所有节点,然后排个序
this.k = k;
preOrder(root);
return k_value;
}
public void preOrder(TreeNode root) {
if (root == null)
return;
preOrder(root.right);
k--;
if(k == 0) {
k_value = root.val;
return;
}
preOrder(root.left);
}
总结
1)掌握树的递归结构,才能去自定义遍历方式。
2)掌握好树的遍历操作,才能在此基础上完成其它自定义操作。
3)一般在树做操作,都需要涉及到回溯和剪枝。
4)第一种方法是暴力解法,如果想不出来可以快速解题。空间复杂度和时间复杂度都很高,分别为O(N),N为节点数;空间复杂度为O(Nlog2N),这已经是最快的排序时间复杂度。
5)第二种方法要求我们熟练掌握二叉树的遍历操作。