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?

Solution1:二分查找

思路:在当前结点,数左子树的结点总数num,(1)如果不到k - 1,说明在右子树里面;(2)如果等于k-1,当前结点就是kthSmallest;(3)如果大于k-1,说明就在左子树里面,递归继续在左子树里面找(k-num-1)thSmallest,不用管右子树了。
时间复杂度: 如果一直是情况(3),就是O(N),如果一直是情况(1)必然是O(N^2),

Average: 当是树是基本平衡的时候,T(N) = T(N / 2) + O(N/2) => O(N)
worst: O(N ^ 2) 比如只有左子树,target还在最左下
Time Complexity: O(N) Space Complexity: O(N)

Solution2.a:二分查找 + augmented TreeNode data structure

(不如2.b)
思路:将结点的结构多加一个lCount,记录sub_left_tree的结点总数。
这样在每次调用kthSmallest()时,不用每次再count,直接看lCount二分就能找到,是O(logN)。
但是这是在新树已经建立好的情况下,如果是按题目的话建立树的过程这里对整体树复制,因为用Iterative由上倒下count需要O(logN),整体也还是需要O(NlogN);如果是从的数组建立的话,排序O(NlogN) + 累积Count(O(N)) + 建树O(N)

2.b 思路与a大体相同,count_all_sub 和 count_left_sub是一样的。用分治法建树只需要O(N),由低向上count

Solution3.a:In-order Traversal (recursive)

Time Complexity: O(k), worst case O(N) Space Complexity: O(N) 递归缓存

Solution3.b:In-order Traversal (iterative)

Time Complexity: O(k) worst case O(N) Space Complexity: O(N)

Solution1 Code:

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        
        int left_count = countSubTree(root.left);
        if(left_count == k - 1) {
            return root.val;
        }
        else if(left_count > k - 1) {
            // kthSmallest element in the left tree
            return kthSmallest(root.left, k);
        }
        else {
            // kthSmallest element in the right tree
            return kthSmallest(root.right, k - left_count - 1);
        }
    }
    
    private int countSubTree(TreeNode root) {
        if(root == null) return 0;
        return countSubTree(root.left) + countSubTree(root.right) + 1;
    }
}

Solution2 Code:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class TreeNodeWithCount {
    int val;
    int lCount;
    TreeNodeWithCount left;
    TreeNodeWithCount right;
    
    TreeNodeWithCount(int x) { val = x; }
}

public class Solution {

    public int kthSmallest(TreeNode root, int k) {
        if(root == null) return -1;
        TreeNodeWithCount rootWithCount = createBSTWithCount(root);
        return kthSmallestWithCount(rootWithCount, k);
    }

    public TreeNodeWithCount createBSTWithCount(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        TreeNodeWithCount rootWithCount = null;
        while(!queue.isEmpty()) {
            TreeNode node = queue.poll();
            
            TreeNodeWithCount nodeWithCount = new TreeNodeWithCount(node.val);
            rootWithCount = insertBSTWithCount(rootWithCount, nodeWithCount);
            
            if(node.left != null) queue.add(node.left);
            if(node.right != null) queue.add(node.right);
        }
        return rootWithCount;
    }

    public TreeNodeWithCount insertBSTWithCount(TreeNodeWithCount rootWithCount, TreeNodeWithCount nodeWithCount) {
        TreeNodeWithCount cur = rootWithCount, parent = rootWithCount;
        while(cur != null) {
            parent = cur;
            if(nodeWithCount.val < cur.val) {
                cur.lCount++;
                cur = cur.left;
            } else {
                cur = cur.right;
            }
        }
        if(rootWithCount == null) {
            rootWithCount = nodeWithCount;
        } else if(nodeWithCount.val < parent.val) {
            parent.left = nodeWithCount;
        } else {
            parent.right = nodeWithCount;
        }
        return rootWithCount;
    }

    public int kthSmallestWithCount(TreeNodeWithCount rootWithCount, int k) {
        while(rootWithCount != null) {
            if(k == rootWithCount.lCount + 1) {
                return rootWithCount.val;
            } else if(k <= rootWithCount.lCount) {
                rootWithCount = rootWithCount.left;
            } else {
                k = k - rootWithCount.lCount - 1;
                rootWithCount = rootWithCount.right;
            }
        }
        return -1;
    }
}

Solution2.b Code:

   public class Solution {
        public int kthSmallest(TreeNode root, int k) {
            TreeNodeWithCount rootWithCount = buildTreeWithCount(root);
            return kthSmallest(rootWithCount, k);
        }
        
        private TreeNodeWithCount buildTreeWithCount(TreeNode root) {
            if (root == null) return null;
            TreeNodeWithCount rootWithCount = new TreeNodeWithCount(root.val);
            rootWithCount.left = buildTreeWithCount(root.left);
            rootWithCount.right = buildTreeWithCount(root.right);
            if (rootWithCount.left != null) rootWithCount.count += rootWithCount.left.count;
            if (rootWithCount.right != null) rootWithCount.count += rootWithCount.right.count;
            return rootWithCount;
        }
        
        private int kthSmallest(TreeNodeWithCount rootWithCount, int k) {
            if (k <= 0 || k > rootWithCount.count) return -1;
            if (rootWithCount.left != null) {
                if (rootWithCount.left.count >= k) return kthSmallest(rootWithCount.left, k);
                if (rootWithCount.left.count == k-1) return rootWithCount.val;
                return kthSmallest(rootWithCount.right, k-1-rootWithCount.left.count);
            } else {
                if (k == 1) return rootWithCount.val;
                return kthSmallest(rootWithCount.right, k-1);
            }
        }
        
        class TreeNodeWithCount {
            int val;
            int count;
            TreeNodeWithCount left;
            TreeNodeWithCount right;
            TreeNodeWithCount(int x) {val = x; count = 1;};
        }
    }

Solution3.a Code:

class Solution {
    private int result;
    private int count;
    
    public int kthSmallest(TreeNode root, int k) {
        count = k;
        helper(root);
        return result;
    }
    
    public void helper(TreeNode node) {
        if(node == null) return;
        
        helper(node.left);
        count--;
        if (count == 0) {
            result = node.val;
            return;
        }
        helper(node.right);    
    }
}

Solution3.a.2 Round1 Code:

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        TreeNode result = dfs(root, k);
        if(result == null) return 0;
        else return result.val;
    }
    
    private int count = 0;
    
    private TreeNode dfs(TreeNode root, int k) {
        if(root == null) return null;
        
        TreeNode l_res = dfs(root.left, k);
        if(l_res != null) return l_res;
        
        count++;
        if(count == k) return root;
        
        TreeNode r_res = dfs(root.right, k);
        if(r_res != null) return r_res;
        
        return null;
    }
}

Solution3.b Code:

class Solution {
    public int kthSmallest(TreeNode root, int k) {
        int count = k;
        TreeNode cur = root;
        Stack<TreeNode> stack = new Stack<>();
        while(cur != null || !stack.empty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            count--;
            if(count == 0) return cur.val;
            
            cur = cur.right;
        }
        return Integer.MIN_VALUE; //not found
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容