230. Kth Smallest Element in a BST

题目:

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.

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?

Hint:

  1. Try to utilize the property of a BST.
  2. What if you could modify the BST node's structure?
  3. The optimal runtime complexity is O(height of BST).

题意:

给定一个二叉搜索树,写一个功能kthSmallest用来找到该二叉树中第K小的元素。

二叉搜索树:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。即根节点的值是中间值,左子树的值均小于根节点的值,右子树的值均大于根节点的值。

note:

可以假设k总是有效的,1 ≤ k ≤二叉搜索树总的节点数量。

Follow up:

如果BST的修改(插入/删除)操作十分频繁,并且需要频繁地找出第k小的元素,应该怎样优化kthSmallest函数?

Hint:

1、尝试利用BST的属性。

2、如果你可以修改BST节点的结构时,应该怎样做?

3、最优时间复杂度应该是O(BST的高度)。


思路一:

利用堆栈实现,利用堆栈实现中序遍历,首先找到最左边的元素,即为该二叉搜索树的最小值,将从根节点开始的所有左子树的根节点都保存在堆栈中,以备左右子树切换时使用,每找到一个左子树叶子节点,则k减一,病切换到右子树去查询,直到k为0为止,返回该节点的值即可。非递归版。

代码:java版:2ms

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int kthSmallest(TreeNode root, int k) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode node = root;
        while (node.left != null) { //将所有的左子树入栈
            stack.push(node);
            node = node.left;
        }
        
        while (k>0 && (node!=null || !stack.isEmpty())) {
            if (node == null) {  //如果节点为空
                node = stack.pop();  //找到其父节点
                if (--k == 0) //找到第k小的元素
                    return node.val;
                node = node.right;  //找右子树
            } else {  
                stack.push(node);
                node = node.left;
            }
        }
        return node.val;
    }
}
代码:C++版:20ms

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        int cnt = 0;
        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 0;
    }
};


思路二:

利用计算二叉树节点数量的子函数,计算出根节点左子树的总的节点数量,然后比较左子树节点数量与k值得大小,如果k值小于左子树节点数目,则说明该值在左子树中,继续对左子树进行迭代处理,如果大于,则说明k值最小的节点在右子树中,则对右子树进行迭代处理,并且减掉前面左子树数目的k值。

代码:C++版:24ms

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        if (root == NULL) return 0;
        
        int leftSize = treeSize(root->left);
        if (k == leftSize+1) {
            return root->val;
        } else if (leftSize >= k) {
            return kthSmallest(root->left, k);
        } else {
            return kthSmallest(root->right, k-leftSize-1);
        }
    }
    
    int treeSize(TreeNode* root) {  //计算根节点下有多少节点
        if (root == NULL) return 0;
        return 1 + treeSize(root->left) + treeSize(root->right);
    }
};


思路三:

直接递归实现,依然基于中序遍历的思想。

代码:C++版:20ms

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int kthSmallest(TreeNode* root, int k) {
        return kthSmallestDFS(root, k);
    }
    int kthSmallestDFS(TreeNode* root, int &k) {
        if (!root) return -1;
        int val = kthSmallestDFS(root->left, k);
        if (!k)
            return val;
        if (!--k) 
            return root->val;
        return kthSmallestDFS(root->right, k);
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值