【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

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.
Example 1:
Input: root = [3,1,4,null,2], k = 1
  3
 / \
1   4
 \
  2
Output: 1

Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
        5
       / \
      3   6
     / \
    2   4
   /
  1
Output: 3

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?


C++

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
 
/*
方法一:中序遍历递归法
BST中序遍历之后为从小到大排列
中序遍历递归法,不是最优的,因为是遍历完之后在给出的结果(可用迭代法进行改进,参考题目 Validate Binary Search Tree)
注:可在递归中加入判断进行减枝
*/
class Solution
{
public:
    int kthSmallest(TreeNode* root, int k)
    {
        vector<int> nodes;
        inorder(root, nodes);
        return nodes[k-1];
    }
   
    void inorder(TreeNode* root, vector<int>& nodes)
    {
        if(root == nullptr) return; //递归的出口
       
        inorder(root->left, nodes);
        nodes.push_back(root->val);
        inorder(root->right, nodes);
    }
};
/*
方法二:中序遍历迭代法
在遍历的过程中统计数量
*/
class Solution
{
public:
    int kthSmallest(TreeNode* root, int k)
    {
        int cnt = 0;
        stack<TreeNode*> s;
        TreeNode *p = root;
        while (!s.empty() || p)
        {
            if(p) //左结点不为空时
            {
                s.push(p);   //入栈
                p = p->left; //指向下一个左结点
            }
            else //左结点为空时
            {
                p = s.top();
                cnt++; //统计数目(遍历到了要访问的父结点)
                if (cnt == k) return p->val;
                s.pop();
               
                p = p->right;  //指向右结点             
            }
          
        }
        return 0;
    }
};
/*
方法三:分治法
首先计算出左子树的结点个数总和cnt,
如果k小于等于左子树结点总和cnt,说明第k小的元素在左子树中,直接对左子结点调用递归即可。
如果k大于cnt+1,说明目标值在右子树中,对右子结点调用递归函数
如果k等于cnt+1,则当前结点即为所求
*/
class Solution
{
public:
    int kthSmallest(TreeNode* root, int k)
    {
        int cnt = count(root->left);
        if (k <= cnt)
        {
            return kthSmallest(root->left, k);
        }
        else if (k > cnt + 1)
        {
            return kthSmallest(root->right, k - cnt - 1); //注意此处变为k - (cnt-1)
        }
        else
            return root->val;
    }
    int count(TreeNode* node)
    {
        if (!node) return 0;
        return 1 + count(node->left) + count(node->right);
    }
};
/*
Follow up: 假设该BST被修改的很频繁,而且查找第k小元素的操作也很频繁,问我们如何优化
方法:改进方法三
修改原树结点的结构,使其保存包括当前结点和其左右子树所有结点的个数,
这样我们使用的时候就可以快速得到任何左子树结点总数来帮我们快速定位目标值了
分析:
对于查找很频繁的情况,由于保存了结点个数,每次查找时,不需要递归统计结点个数,这样可以节省大量时间
对于修改很频繁的情况,插入或者删除某个结点时,需更新其所有祖先结点,所以该方法并不太适用于修改很频繁的情况
*/
 
class Solution
{
private:
    struct MyTreeNode
    {
        int val;
        int count;
        MyTreeNode *left;
        MyTreeNode *right;
        MyTreeNode(int x) : val(x), count(1), left(NULL), right(NULL) {}
    };
    
public:
    int kthSmallest(TreeNode* root, int k)
    {
        MyTreeNode *node = build(root);
        return helper(node, k);
    }
    
    MyTreeNode* build(TreeNode* root)
    {
        if (!root)
            return NULL;
        else
        {
            MyTreeNode *node = new MyTreeNode(root->val); //count在构造函数中被初始化为1
            node->left = build(root->left);
            node->right = build(root->right);       
            if (node->left) node->count += node->left->count; //统计数量
            if (node->right) node->count += node->right->count;     
            
            return node;
        }  
    }
   
    int helper(MyTreeNode* node, int k)
    {
        if (node->left)
        {
            int cnt = node->left->count; //左结点存储了当前结点左子树的所有结点个数
            if (k <= cnt)
                return helper(node->left, k);
            else if (k > cnt + 1)
                return helper(node->right, k - 1 - cnt);
            else
                return node->val;
        }
        else
        {
            if (k == 1)
                return node->val;
            else
                return helper(node->right, k - 1);
           
        }
    }
};

参考:http://www.cnblogs.com/grandyang/p/4620012.html

转载于:https://www.cnblogs.com/wikiwen/p/10225851.html

【LeetCode 剑指offer刷题】树题16:Kth Smallest Element in a BST相关推荐

  1. 【LeetCode 剑指offer刷题】树题6:28 对称二叉树(101. Symmetric Tree)

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 101. Symmetric Tree /**  * Definition for a binary tree no ...

  2. 【LeetCode 剑指offer刷题】树题19:8 二叉树中序遍历的下一个结点

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 8 二叉树中序遍历的下一个结点 题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注 ...

  3. 【LeetCode 剑指offer刷题】树题4:104 Maximum Depth of Binary Tree

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 104. Maximum Depth of Binary Tree Given a binary tree, fin ...

  4. 【LeetCode 剑指offer刷题】数组题2:57 有序数组中和为s的两个数(167 Two Sum II - Input array is sorted)...

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 57 有序数组中和为s的两个数 题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是 ...

  5. 【LeetCode 剑指offer刷题】字符串题6:67 把字符串转成整数

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 67 把字符串转成整数 题目描述 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数. 数值为0或者字符 ...

  6. 【LeetCode 剑指offer刷题】回溯法与暴力枚举法题6:Number of Islands

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Number of Islands Given a 2d grid map of '1's (land) and ' ...

  7. 【LeetCode 剑指offer刷题】查找与排序题14:Wiggle Sort(系列)

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Wiggle Sort II Given an unsorted array nums, reorder it su ...

  8. 【LeetCode 剑指offer刷题】查找与排序题12:Top K Frequent Elements

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) Top K Frequent Elements Given a non-empty array of integer ...

  9. 【LeetCode 剑指offer刷题】矩阵题1:4 有序矩阵中的查找( 74. Search a 2D Matrix )(系列)...

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 74. Search a 2D Matrix Write an efficient algorithm that s ...

最新文章

  1. 在Ubuntu 12.04 桌面上设置启动器(快捷方式)
  2. php 前端及时同步,php与前端界面的实时通信
  3. C/S框架-发布和部署WebService
  4. 当你刷新当前Table时,刷新后如何回到你上一次所在位置呢?
  5. HtmlAgilityPack的简单使用
  6. 龙之谷哪个服务器最多,龙之谷哪些服务器数据互通 龙之谷数据互通详情介绍...
  7. 成绩的案例java_java-成绩案例
  8. Java设计模式---模板设计模式
  9. 项目开发文档是必须的
  10. 计算机毕业设计Java新能源汽车故障分析2021(源码+系统+mysql数据库+Lw文档)
  11. 有道单词本手机和电脑同步问题
  12. 计算机excel无法打开,电脑excel打不开的解决方法
  13. case when 语句用法
  14. 洛谷P3975 弦论
  15. Java实现牛牛的水杯
  16. 雇佣兵问题(Python解答)
  17. android音频系统(7):通话过程中的音频输出设备切换
  18. pthread_cond_signal与pthread_cond_broadcast的使用区别
  19. Ubuntu20.04安装CUDA+CUDNN+Conda+PyTorch
  20. Zynq-7000 AMP运行模式下的软件切换及多版本固化运行

热门文章

  1. MEDC2007北京游记 - WindowsMobile Ophone
  2. Android 百度鹰眼轨迹SDK(v2.1.6)
  3. 转载 C++实现的委托机制
  4. express框架安装步骤
  5. Android EditText禁止复制粘贴
  6. 监控软件nagios错误总结
  7. (二)把域服务升级和迁移到Windows Server 2012 R2上
  8. PHP高手如何修炼?
  9. 剑指Offer(Java实现)栈的压入、弹出序列
  10. 深入理解 Java内存模型