题目链接在此
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:
- Try to utilize the property of a BST.
- What if you could modify the BST node's structure?
- The optimal runtime complexity is O(height of BST).
最直观的解法是中序遍历,找到所寻找的那个节点。时间复杂度是O(k)。
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() {}
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
vector<int> v;
inorder(root, v, k);
return v[k - 1];
}
private:
void inorder(TreeNode* root, vector<int>& v, int k) {
if (root == NULL || v.size() == k)
return;
inorder(root->left, v, k);
v.push_back(root->val);
inorder(root->right, v, k);
}
};
但是让我不理解的是,即使树的结构有这么一个属性,如果节点的增删频繁,依然需要实时地花费时间重新度量这个属性。这样一来,
时间复杂度是否真的降低了呢?
以下是未加新属性的一份代码,而是实时统计一棵树的左子树数量。
class Solution2 {
public:
int kthSmallest(TreeNode* root, int k) {
// 若k == node.leftCnt + 1:则返回node
// 否则,若k > node.leftCnt:则令k -= node.leftCnt + 1,令node = node.right
// 否则,node = node.left
if (root == NULL)
return 0;
int leftCount = countTree(root->left);
if (k == leftCount + 1)
return root->val;
else if (leftCount >= k)
return kthSmallest(root->left, k);
else
return kthSmallest(root->right, k - leftCount - 1);
return root->val;
}
private:
int countTree(TreeNode* root){
if (root == NULL)
return 0;
return 1 + countTree(root->left) + countTree(root->right);
}
};