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?

有两种办法,可以使用二分法来查找,也利用深度优先遍历的变种。

二分法

对于每一个节点,左边的节点都是小于它的,右边的节点都是大于它的。
利用这一点,如果当前节点的左子树有k-1个节点,那当前节点就是我们要找的节点。
如果当前节点左子树中有k个或多于k个节点,那意味着我们要找的节点是左子树第k个最小的,把根节点指向左子树的根节点。
如果当前节点的左子树中有小于k-1个节点,就说明我们要在右子树中找第k-(左子树节点数+1)个小的节点。

var kthSmallest = function(root, k) {
    var help = function(node) {
        var num = 0;
        if (node) {
            var s = [node];
            while (s.length!==0) {
                var temp = s.pop();
                num++;
                if (temp.left)
                    s.push(temp.left);
                if (temp.right)
                    s.push(temp.right);
            }
        }
        return num;
    };
    while (root) {
        var leftNum = help(root.left);
        if (leftNum===(k-1)) 
            return root.val;
        else if (leftNum>=k) {
            root = root.left;
            continue;
        }
        else if (leftNum<(k-1)) {
            k -= leftNum+1;
            root = root.right;
            continue;
        }
    }
};

利用深度优先遍历

这里利用的思想是,左节点一定小于右节点并小于等于父节点,右节点一定大于父节点并小于父节点的父节点。
我们先从根节点开始把所有的左节点压到栈里,这时栈顶的这个左节点一定是整棵树中最小的。
在出栈时,k-1, 如果出栈的节点有右节点,把它入栈因为它一定比现在栈顶的元素小,然后继续把这个节点的左子节点压入栈。

var kthSmallest = function(root, k) {
    var st = [];
    while (root !== null) {
        st.push(root);
        root = root.left;
    }
    while (k !== 0) {
        var n = st.pop();
        k--;
        if (k === 0) return n.val;
        var right = n.right;
        while (right !== null) {
            st.push(right);
            right = right.left;
        }
    }
    return -1;
};

你可能感兴趣的:(230. Kth Smallest Element in a BST)