题目描述
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路1:对于二叉搜索树,它的中序遍历数值是递增排序的。先进行递归中序,存入数组,然后从数组中取出第k大的数。尤其注意边界条件,即k与二叉树节点数的大小!若k>总节点数,就返回nullpter。
class Solution {
public:
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if (pRoot == nullptr || k<=0)
return nullptr;
vector<TreeNode*> arr;
inOrder(pRoot, arr);
if (k > arr.size()) //判断k与数组元素大小
return nullptr;
return arr[k - 1];
}
void inOrder(TreeNode* pRoot, vector<TreeNode*>& arr) { //中序遍历,存入数组中
if (pRoot == nullptr)
return;
inOrder(pRoot->left, arr);
arr.push_back(pRoot);
inOrder(pRoot->right, arr);
}
};
思路2:定义一个TreeNode*来存储第k个节点,但也是完全遍历完所有节点后再退出递归。
class Solution {
public:
TreeNode* res = nullptr;
int count = 0;
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if (pRoot == nullptr)
return nullptr;
KthNode(pRoot->left, k);
if (++count == k)
res = pRoot;
KthNode(pRoot->right, k);
return res;
}
};
思路3:优化思路2 解法,当找到第k个节点时就跳出递归,而不必对所有值进行运算,降低时间复杂度。
class Solution {
public:
TreeNode* res = nullptr;
int count = 0;
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if (pRoot == nullptr)
return nullptr;
KthNode(pRoot->left, k);
if (++count == k)
res = pRoot;
if(count<k) //加上if(count<k)判断后,如果满足count==k了就直接跳出递归!如果直接写成KthNode(pRoot->right, k);会遍历完所有节点,再退出
KthNode(pRoot->right, k);
return res;
}
};
也可以写成如下方式:
对于 if (node != nullptr) return node;
的理解:
如果没有if(node != null)
这句话 那么那个root就是返回给上一级的父结点的,而不是递归结束的条件了,有了这句话过后,一旦返回了root,那么node就不会为空了,就一直一层层的递归出去到结束了。
class Solution {
public:
int count = 0;
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if (pRoot == nullptr || k <= 0)
return nullptr;
TreeNode* node = nullptr;
node = KthNode(pRoot->left, k);
if (node != nullptr) //递归结束的条件。当count<k时,node=nullptr;只有当count==k时,node==第k个pRoot,便返回。
return node;
count++;
if (count == k) //当count==k时,找到了对应节点,但是递归并没有结束,所以需要将结果通过node逐层返回。
return pRoot;
node = KthNode(pRoot->right, k);
if (node != nullptr)
return node;
}
};
思路4:DFS,使用栈,中序遍历的非递归方式。
class Solution {
public:
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if (pRoot == nullptr || k <= 0)
return nullptr;
stack<TreeNode*> s;
int count = 0;
while (pRoot!=nullptr || !s.empty())
{
while (pRoot!=nullptr)
{
s.push(pRoot);
pRoot = pRoot->left; //将最左一条子树依次压入栈,后面根据左子树出栈顺序来判断并压入每一个节点对应的右子树
}
if (!s.empty()) {
pRoot = s.top();
s.pop();
if (++count == k) //当count == k,就返回并退出
return pRoot;
pRoot = pRoot->right; //栈顶元素向右子树遍历
}
}
return nullptr;
}
};