剑指offer-二叉搜索树的第K个节点

剑指offer-二叉搜索树的第K个节点

题目描述

给定一颗二叉搜索树,请找出按序排列的第K个的节点。

输入:

    5
   / \
  3   7
 / \ / \
2  4 6  8

输出:

若K=3,则输出4

解题思路

二叉搜索树性质可知,左子树所有节点均小于当前节点,右子树节点均大于当前节点。可以根据左子树数量确定第K个节点位置。

1、若左子树节点数为K,则第K个节点为左子树的最右节点。
2、若左子树节点数为K-1,则第K个节点为当前节点。
3、若左子树节点数大于K,则第K个加点在左子树中,递归求左子树第K个节点即可。
4、若左子树节点数小于K-1,假设为S,则第K个节点为右子树第K-S-1个节点, 递归求右子树第K-S-1个节点即可。

基于以上思路,代码实现如下:

//根据先序遍历求二叉树节点总数
int NodesOfTree(TreeNode *node) {
    if (NULL == node) {
        return 0;
    }

    int res = 1;
    res += NodesOfTree(node->left);
    res += NodesOfTree(node->right);
    return res;
}

//求取二叉树最大子节点
TreeNode *GetMaxNodeOfTree(TreeNode *root) {
    if (NULL == root) {
        return NULL;
    }

    while (NULL != root->right) {
        root = root->right;
    }

    return root;
}

//主程序
TreeNode* KthNode(TreeNode* pRoot, int k)
{
    if (NULL == pRoot) {
        return NULL;
    }

    int leftCounts = NodesOfTree(pRoot->left); //获取左子树节点数
    if (leftCounts == k-1) { //若左子树节点数为K-1
        return pRoot;
    } else if (leftCounts == k) { //若左子树节点数为K
        return GetMaxNodeOfTree(pRoot->left);
    } else if (leftCounts > k) { //若左子树节点数大于K
        return KthNode(pRoot->left, k);
    } else { //若左子树节点数小于K-1
        return KthNode(pRoot->right, k-leftCounts-1);
    }
}

TreeNode定义如下:

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
        val(x), left(NULL), right(NULL) {
}

========================================================

另附上大神思路:

由于二叉树中序遍历所得到的节点顺序即为大小排序,故可以按中序遍历方式求解。代码如下:

int count = 0; //全局变量记录当前遍历至第几个节点,**其实可以作为引用参数传递给函数
TreeNode *KthNode(TreeNode *pRoot, int k) {
    if (NULL != pRoot) {
        TreeNode *res = KthNode(pRoot->left, k);
        if(NULL != res) {
            return res;
        }

        if (++count == k) {
            return pRoot;
        }

        return KthNode(pRoot->right, k);
    }

    return NULL;
}

大神代码就是精简,还需要继续学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值