栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

剑指offer 54:二叉搜索树中第K小的元素

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

剑指offer 54:二叉搜索树中第K小的元素

剑指offer 54

题目:

方法一:BST的中序遍历

二叉搜索树重要性质:BST的中序遍历是升序排列 !
递归三部曲:
1.参数root和k,不需要返回值,改变成员变量rank和结果r就行
2.终止条件null则return
3.判断当前rank是否等于k

import java.util.*;
public class Solution {
    int rank=0;
    int r=-1;
    public int KthNode (TreeNode root, int k) { 
        // 中序是升序排列
        check(root,k);
        return r;
        
    }
    
    void check(TreeNode root,int k){
        if(root==null || k<=0 ){ 
        return;
    }
        check(root.left,k);
        // 中序
        rank++;
        if(rank==k){
            r=root.val;
            return;
        }
        check(root.right,k);
    }
}
    

时间复杂度:O(H+k),其中 H 是树的高度,最小值 O(logN+k),最大值 O(N+k)

当k<=0时,在终止条件中判定并return, 当k大于节点个数时,会遍历到null为止,并不会进入if(rank==k){...} ,所以r值并没有改变,返回 r= -1

改进思路:

方法一中,之所以需要中序遍历前 k 个元素,是因为我们不知道子树的结点数量,不得不通过遍历子树的方式来获知。
找到第 k 小的元素,或者说找到排名为 k 的元素,如果想达到对数级复杂度,关键也在于每个节点得知道他自己排第几。
这样就可以将搜索的时间复杂度降到 O(logN) 了。

那么,如何让每一个节点知道自己的排名呢?
每个节点需要记录,以自己为根的这棵二叉树有多少个子节点。
在实现中,可以将以每个结点为根结点的子树的结点个数存储在哈希表中or 使个数作为节点的属性之一。

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        MyBst bst = new MyBst(root);
        return bst.kthSmallest(k);
    }
}

class MyBst {
    TreeNode root;
    Map nodeNum;

    public MyBst(TreeNode root) {
        this.root = root;
        this.nodeNum = new HashMap();
        countNodeNum(root);
    }

    // 返回二叉搜索树中第k小的元素
    public int kthSmallest(int k) {
        TreeNode node = root;
        while (node != null) {
            int left = getNodeNum(node.left);
            if (left < k - 1) {
                node = node.right;
                k -= left + 1;
            } else if (left == k - 1) {
                break;
            } else {
                node = node.left;
            }
        }
        return node.val;
    }

    // 统计以node为根结点的子树的结点数
    private int countNodeNum(TreeNode node) {
        if (node == null) {
            return 0;
        }
        nodeNum.put(node, 1 + countNodeNum(node.left) + countNodeNum(node.right));
        return nodeNum.get(node);
    }

    // 获取以node为根结点的子树的结点数
    private int getNodeNum(TreeNode node) {
        return nodeNum.getOrDefault(node, 0);
    }
}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/959006.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号