首页 > 试题广场 >

二叉搜索树的第k个节点

[编程题]二叉搜索树的第k个节点
  • 热度指数:54386 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一棵点数为n 二叉搜索树,请找出其中的第 k 小的TreeNode结点值。
1.返回第k小的节点值即可
2.不能查找的情况,如二叉树为空,则返回-1,或者k大于n等等,也返回-1
3.保证n个节点的值不一样


数据范围: ,树上每个结点的值满足
进阶:空间复杂度 ,时间复杂度


如输入{5,3,7,2,4,6,8},3时,二叉树{5,3,7,2,4,6,8}如下图所示:

该二叉树所有节点按结点值升序排列后可得[2,3,4,5,6,7,8],所以第3个结点的结点值为4,故返回对应结点值为4的结点即可。

示例1

输入

{5,3,7,2,4,6,8},3

输出

4
示例2

输入

{},1

输出

-1

备注:
当树是空

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param proot TreeNode类 
# @param k int整型 
# @return int整型
#
class Solution:
    def KthNode(self , proot: TreeNode, k: int) -> int:
        # corner case
        if not proot: return -1

        stk, trav = [], proot
        while stk&nbs***bsp;trav:
            while trav:
                stk.append(trav)
                trav = trav.left
                
            k -= 1
            if not k: return stk[-1].val
        
            trav = stk[-1].right
            stk.pop()
            
        return -1

发表于 2021-11-24 10:41:02 回复(1)
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param proot TreeNode类
     * @param k int整型
     * @return int整型
     */
    //空间o
,时间 <= o(n)
    //定义两个属性记录中序遍历的值
    int res = -1;
    int count;
    public int KthNode (TreeNode proot, int k) {
        // write code here
        if(proot==null) return -1;
        count = k;
        dfs(proot);
        return res;
    }
    //中序遍历,是搜索树从小到大的值遍历
    void dfs(TreeNode proot){
        //当res不等于-1时表示已经找到第k小的值了,直接返回,减枝
        if(res!=-1||proot==null) return;
        
        dfs(proot.left);
        //判断当前节点是否为第k小的节点
        if(--count==0){
            res = proot.val;
            return;
        }
        dfs(proot.right);
    }
}
发表于 2022-07-13 11:25:58 回复(0)
Morris中序遍历
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    public int KthNode (TreeNode proot, int k) {
        // write code here
      TreeNode cur = proot,mostRight = null;
      int curIndex = 0;
      while(cur != null){
        mostRight = cur.left;
        if(mostRight!=null){
          while(mostRight.right!=null && mostRight.right!=cur){
            mostRight = mostRight.right;
          }
          // 第一次遍历cur
          if(mostRight.right==null){
            mostRight.right = cur;
            cur = cur.left;
            continue;
          // 第二次遍历cur
          } else {
            mostRight.right = null;
          }
        }
        if(++curIndex == k){
          return cur.val;
        }
        cur = cur.right;
      }
      return -1;
    }
}


发表于 2022-01-27 11:53:23 回复(0)
import java.util.*;

public class Solution {
    //    由于这是一棵二叉搜索树,因此很容易考虑到直接进行中序遍历,将结果放到ArrayList中
    //    这里需要注意:ArrayList的起始角标是0,
    //    因此如果k的大小在ArrayList的容量大小范围内,返回size-1处的数值
    //    否则,返回-1
    private List<Integer> inOrderSet = new ArrayList<>();
    public int KthNode (TreeNode proot, int k) {
        //    如果是空树,或者k == 0,返回 -1
        if(proot == null || k == 0)
            return -1;
        
        //    中序遍历,结果会保存到ArrayList中
        inOrder(proot);
        
        //    如果k的大小超过了ArrayList的容量大小,返回-1
        if(k > inOrderSet.size())
            return -1;
        
        //    否则,说明k的大小在ArrayList的大小范围内,返回size-1处的数值
        return inOrderSet.get(k - 1);
    }
    
    //    中序遍历【中序遍历左,根结点,中序遍历右】
    private void inOrder(TreeNode root){
        if(root == null)
            return ;
        
        inOrder(root.left);
        inOrderSet.add(root.val);
        inOrder(root.right);
    }
}

发表于 2021-11-21 21:26:35 回复(0)
//二叉排序树的中序遍历就能得到从小到大的数放到数组中,要第几个直接取就ok了
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    void Inorder(TreeNode*proot)
    {
        if(proot==NULL)
            return;
        Inorder(proot->left);
        nums.push_back(proot->val);
        Inorder(proot->right);
    }
    int KthNode(TreeNode* proot, int k) {
        // write code here
        if(proot==NULL)
        {
            return -1;
        }
        Inorder(proot);
        if(k>nums.size()||k<=0)
            return -1;
        return nums[k-1];
    }
    private:
        vector<int>nums;
};


发表于 2022-03-12 13:22:21 回复(0)
迭代版中序遍历,在弹栈的时候如果发现这是第k个数就直接返回
import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    public int KthNode (TreeNode proot, int k) {
        // write code here
        Stack<TreeNode> stack = new Stack<>();
        int rank = 1;
        while(!stack.isEmpty() || proot != null){
            while(proot != null) {
                stack.push(proot);
                proot = proot.left;
            }
            if(!stack.isEmpty()){
                proot = stack.pop();
                if(rank == k) return proot.val;
                rank ++;
                proot = proot.right;
            }
        }
        return -1;
    }
}

发表于 2021-11-20 19:25:35 回复(0)
由于是二叉搜索树,所以它的中序遍历是顺序的,将中序遍历结果放入数组,则第k-1个元素即为所求元素;
classSolution {
public:
    intKthNode(TreeNode* proot, intk) {
        // write code here
        if(proot == nullptr) return-1;
        vector<int> vInorder;
        InorderTrevase(vInorder,proot);
        if(k<= 0|| k > vInorder.size()) return-1;
        else return vInorder.at(k-1);
    }
    voidInorderTrevase(vector<int> & vInorder,TreeNode* pNode)
    {
        if(pNode == nullptr) return;
        InorderTrevase(vInorder, pNode->left);
        vInorder.push_back(pNode->val);
        InorderTrevase(vInorder, pNode->right);
    }
};

发表于 2022-08-19 23:56:11 回复(0)
public class Solution {
    // res -- 保存返回值,count -- 统计次数(第几小)
    int res = -1, count = 0;
    public int KthNode (TreeNode proot, int k) {
        if (proot == null) return res;
        inorder(proot, k);
        return res;
    }

    public void inorder(TreeNode proot, int k) {
        // 当遍历到节点为空或者超过k时,返回
        if (proot == null || count > k) return;
        inorder(proot.left, k);
        // 判断是否是需要的第k小
        if (++count == k) res = proot.val;
        inorder(proot.right, k);
    }
}
发表于 2022-08-17 20:01:15 回复(1)
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    vector<int> res;//用于保存二叉搜索树的节点的值
    void InOrder(TreeNode* proot){
        //中序遍历
        if(proot){
            InOrder(proot->left);
            res.push_back(proot->val);
            InOrder(proot->right);
        }
    }
    int KthNode(TreeNode* proot, int k) {
        // write code here
        if(!proot) return -1;
        InOrder(proot);
        //注意k值不合规的情况
        if(k==0||k>res.size()) return -1;
        else return res[k-1];
    }
};
常规做法
发表于 2021-12-03 17:12:21 回复(0)
public class Solution {
    /**
     * 中序遍历 正好是按照BST Node的值 从小到大遍历的。
     * 相当于排序
     */
    int i = 0;
    int res = -1;
    public int KthNode(TreeNode proot, int k) {
        dfs(proot,k);
        return res;
    }
    void dfs(TreeNode proot, int k) {
        if (proot == null)
            return;
        //只有符合条件才继续调用,已经找到第k小,后面就不需要遍历了。
        if (i <= k) {
            dfs(proot.left, k);
             i++;
            if(i==k){
                res=proot.val;
                return;
            }
            dfs(proot.right, k);
        }
    }
}   

发表于 2021-12-03 13:47:14 回复(0)

/**

  • struct TreeNode {

  • int val;

  • struct TreeNode *left;

  • struct TreeNode *right;

  • TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}

  • };

  • /
    class Solution {
    public:
    /**

    • 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可

    • @param proot TreeNode类

    • @param k int整型

    • @return int整型

    • /
      void dfs(TreeNode* proot, int k, int& sum, int& res)
      {
      if(proot == nullptr) return ;
      dfs(proot->left, k, sum, res);

      sum ++;
      if(sum == k) res = proot->val;

      dfs(proot->right, k, sum, res);
      return ;

      }
      int KthNode(TreeNode* proot, int k) {
      int sum =0 ;
      int res;
      dfs(proot, k, sum, res);
      if(sum < k || sum == 0 || k==0) return -1;
      return res;
      // write code here
      }
      };

发表于 2023-04-01 10:40:31 回复(0)
/**
 * struct TreeNode {
 *	int val;
 *	struct TreeNode *left;
 *	struct TreeNode *right;
 *	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param proot TreeNode类 
     * @param k int整型 
     * @return int整型
     */
    int KthNode(TreeNode* proot, int k) {
        // 时间复杂度O(N),空间复杂度O(N)
        dfs(proot, k);
        return k == 0 || k > res.size() ? -1 : res[k - 1];
    }
    void dfs(TreeNode *proot, int k) {
        if (proot == nullptr) return;
        dfs(proot->left, k);
        res.push_back(proot->val);  // 中序遍历
        dfs(proot->right, k);
    }
    vector<int> res;
};

发表于 2022-11-11 18:08:13 回复(0)
class Solution {
public:
    void FTree(TreeNode* proot,vector<int>& v)
    {
        if(proot == nullptr)
        {
            return ; //出口
        }
        //中序遍历
        //二叉搜索树的中序遍历就是一个从小到大的顺序
        FTree(proot->left,v);
        v.push_back(proot->val);
        FTree(proot->right,v);
    }

    int KthNode(TreeNode* prootint k) {
        // write code here
        if(!proot || k == 0)
            return -1;
        vector<int> v;
        FTree(proot,v); //中序遍历
        if(v.size() < k)
            return -1;
        //也可以普通的把结点放入vector中
        //然后使用sort也可以达到排序的目的
        //sort(v.begin(),v.end());
        return v[k-1];
       }
};
发表于 2022-10-14 23:02:55 回复(0)
1. 方法一:迭代法
2. 方法二:中序遍历
    // 方法一:迭代法
    public int KthNode1 (TreeNode proot, int k) {
        // write code here
        if(proot == null || k == 0) return -1;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = proot;
        while(cur != null || !stack.isEmpty()){
            while(cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            if(!stack.isEmpty()){
                cur = stack.pop();
                if(--k == 0){
                    return cur.val;
                }
            }
            cur = cur.right;
        }
        return -1;
    }
    // 方法二:中序遍历
    List<Integer> list = new ArrayList<>();
    public int KthNode (TreeNode proot, int k) {
        // write code here
        if(proot == null || k == 0) return -1;
        inOrder(proot);
        return k <= list.size() ? list.get(k-1) : -1;
    }
    private void inOrder(TreeNode proot){
        if(proot == null) return;

        inOrder(proot.left);
        list.add(proot.val);
        inOrder(proot.right);
    }



发表于 2022-08-01 10:38:10 回复(0)
先中序遍历所有的节点获得了单调增加的数值序列,然后判断,时间和空间复杂度都是O(n)。
遍历时,NoneType和int以及List<integer>之间的转换和相加出现了卡壳。
自己的较复杂的方案如下,保证递归时返回的结果必然是list类型。
class Solution:
    def midOrder(self,proot:TreeNode):
        if not proot:
            return
        else:
            rootlist=[]
            rootlist.append(proot.val)
            val_list_left=self.midOrder(proot.left)
            val_list_right=self.midOrder(proot.right)
            if val_list_left is None and val_list_right is None:
                return rootlist
            elif val_list_left is None:
                return rootlist+val_list_right
            elif val_list_right is None:
                return val_list_left+rootlist
            else:
                return val_list_left+rootlist+val_list_right
    def KthNode(self , proot: TreeNode, k: int) -> int:
        # write code here
        val_list=self.midOrder(proot)
        if val_list is None&nbs***bsp;k>len(val_list)&nbs***bsp;k<=0:
            return -1
        else:
            return val_list[k-1]


发表于 2022-04-29 17:01:31 回复(0)
public int KthNode (TreeNode proot, int k) {
        // write code here
        if (proot == null || k == 0)return -1;
        num = k;
        return dfs(proot);
    }

    int num = -1;

    int dfs(TreeNode p) {
        int res = -1;
        if (p.left != null)res = dfs(p.left);
        if (res != -1)return res;
        if (num == 1)return p.val;
        num--;
        if (p.right != null)res = dfs(p.right);
        return res;
    }

编辑于 2022-03-27 22:29:03 回复(0)
/**
 * struct TreeNode {
 *  int val;
 *  struct TreeNode *left;
 *  struct TreeNode *right;
 *  TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 * };
 */
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param proot TreeNode类
     * @param k int整型
     * @return int整型
     */
    int num =0;//当前已搜索过的节点数(包含当前节点)

    //写一个中序遍历即可
    int midSearch(TreeNode* root,int k){
        //抛出异常
        if(root ==nullptr){
            return -1;
        }

        //1.先搜索左子树,出现目标时立刻返回,避免不必要的计算
        int left =midSearch(root->left, k);
        if(left !=-1){
            return left;
        }

        num++;
        //class前添加#define DEBUG后激活测试语句========================
        #ifdef DEBUG
        std::cout<<"num: "<<num<<" value: "<<root->val<<std::endl;
        #endif
        //测试语句截止==================================================

        //2.当前节点出现目标的情况
        if(num ==k){
            return root->val;
        }
       
        //3.最后搜索右子树,出现目标时立刻返回,避免不必要的计算
        int right =midSearch(root->right, k);
        if(right !=-1){
            return right;
        }
       
        //左右子树和目标节点都没有出现目标时才返回-1(k >节点数的情况)
        return -1;
    }

   
    int KthNode(TreeNode* proot, int k) {
        // write code here
        return midSearch(proot, k);        
    }
};
发表于 2024-04-11 20:51:53 回复(0)
#include <vector>
class Solution {
public:
    void inorder(TreeNode* proot,vector<int>&ans){
        if(proot==nullptr){
            return;
        }
        inorder(proot->left, ans);
        ans.push_back(proot->val);
        inorder(proot->right,ans);
    }
    int KthNode(TreeNode* proot, int k) {
    if(proot==nullptr||k==0){
        return -1;
    }
    vector<int>ans;
    inorder(proot,ans);
    if(k>ans.size()){
        return -1;
    }
    return ans[k-1];
    }
};

编辑于 2024-04-09 16:36:31 回复(0)
class Solution:
    def KthNode(self , proot: TreeNode, k: int) -> int:
        # write code here
        res = []
        def inorder(root):
            if not root:
                return
            inorder(root.left)
            res.append(root.val)
            inorder(root.right)
        inorder(proot)
        if k > len(res)&nbs***bsp;k <= 0:
            return -1
        return res[k-1]

发表于 2024-04-07 11:53:29 回复(0)
int cnt;
public int KthNode (TreeNode proot, int k) {
    // write code here
    cnt=k;
    return dfs(proot);

}

public int dfs(TreeNode root){
    if(root==null){
        return -1;
    }
    int left = dfs(root.left);
    if(--cnt==0){
        return root.val;
    }
    int right=dfs(root.right);
    return Math.max(left ,right);
}

编辑于 2024-03-09 15:56:55 回复(0)