【leetcode】【medium】230. Kth Smallest Element in a BST

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.

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?

题目链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/solution/

思路

对BST中序遍历可得到递增序列,因此总体的解题思路是借助中序遍历,在中序是判断当前节点是否是第k个。

法一:递归

/**
 * 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 findk(root, k)->val;
    }
    TreeNode* findk(TreeNode* root, int &k){
        if(!root) return NULL;
        auto l = findk(root->left, k);
        --k;
        if(k==0) return root;
        auto r = findk(root->right, k);
        return (l?l:r);
    }
};

法二:非递归

对中序遍历用非递归方法实现。

我想到的方法:在遍历到父节点时,不能将自身弹出,在将左孩子入栈前先加一个空节点,用来标记当前节点已经历第一次遍历,使得在下一次遍历(中序)的时候访问完就弹出。

别人的方法:套两个while循环,一个管不断将左孩子压栈,一个管整个树的遍历是否完成。

参考:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/solution/er-cha-sou-suo-shu-zhong-di-kxiao-de-yuan-su-by-le/

明显别人的方法比我的优雅许多,里层while就是对压栈思路的原始翻译,两个while嵌套的使用学习下。

非迭代的运行速度更快,可以在找到元素时直接终止程序。

/**
 * 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) {
        stack<TreeNode*> record;
        while(true){
            while(root){
                record.push(root);
                root = root->left;
            }
            root = record.top();
            record.pop();
            if(--k == 0) return root->val;
            else root = root->right;
        }
    }
};

法三:修改节点数据结构

题目最后问频繁根据排名查找元素,可以在节点数据结构中加一个变量:记录以当前节点为根节点的子树上有多少个节点。

则查找时能根据数量关系,直接能确定走向目标节点的路径。

在本题给的数据结构中不太好实现。

发布了126 篇原创文章 · 获赞 2 · 访问量 3729

猜你喜欢

转载自blog.csdn.net/lemonade13/article/details/104476205