230. 二叉搜索树中第K小的元素

介绍

中序遍历:左子树 -> 中 -> 右子树

二叉搜索树:中序遍历可以得到有序的序列

递归法

1.使用函数循环递归处理

2.使用一个数组来保存 k, 保证在个个递归函数中都能看到 看的变化;每访问一个节点,这个数减一,当数组中的数为1时,即访问到了第k小的数

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    public int KthSmallest(TreeNode root, int k) {
        // 辅助结构,当 k == 1 时 表示访问到 第 k个最小的元素
        int[] aux = new int[] { k };
        return Traverse(root, aux);    
    }

    // 递归访问
    public int Traverse(TreeNode node, int[] aux) {
        if(node == null)
        {
            // 用 -1 表示访问到终点
            return -1;
        }

        // 先访问左子树
        {
            var val = Traverse(node.left, aux);
            if(val != -1)
            {
                return val;
            }
        }

        // 访问该节点
        {
            if(aux[0] == 1)
            {
                // 结果
                return node.val;
            }
            aux[0]--;
        }

        // 后访问右子树
        {
            var val = Traverse(node.right, aux);
            if(val != -1)
            {
                return val;
            }
        }

        // 这里是不会走到的根据题意
        return -1;
    }
}

优化:

1.使用 引用传递 k, 确保递归函数都能看到k的变换

2.每次访问右子树时,不用判断直接返回结果

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    public int KthSmallest(TreeNode root, int k) {
        // 辅助结构,当 k == 1 时 表示访问到 第 k个最小的元素
        int aux = k;
        return Traverse(root, ref aux);    
    }

    // 递归访问
    public int Traverse(TreeNode node, ref int aux) {
        if(node == null)
        {
            // 用 -1 表示访问到终点
            return -1;
        }

        // 先访问左子树
        {
            var val = Traverse(node.left, ref aux);
            if(val != -1)
            {
                return val;
            }
        }

        // 访问该节点
        {
            if(aux == 1)
            {
                // 结果
                return node.val;
            }
            aux--;
        }

        // 后访问右子树
        // {
        //     var val = Traverse(node.right, ref aux);
        //     if(val != -1)
        //     {
        //         return val;
        //     }
        // }

        // // 这里是不会走到的根据题意
        // return -1;

        // 一个优化,这里直接返回,如果没找到这里就返回-1
        return Traverse(node.right, ref aux);
    }
}

迭代法

1.使用数据结构Stack,模拟真实的栈处理流程

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left;
 *     public TreeNode right;
 *     public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
public class Solution {
    public int KthSmallest(TreeNode root, int k) {
        // 借助 Stack 模拟栈
        Stack<TreeNode> s = new Stack<TreeNode>();

        // 先让第一个节点进栈,后面流程就处理一致了
        s.Push(root);

        // 根据题意一定存在结果
        // while(s.Count > 0)
        while(true)
        {
            // 访问左子树
            var top = s.Peek();
            if(top != null)
            {
                s.Push(top.left);
                continue;
            }

            // 将null节点弹出栈
            s.Pop();

            // 访问当前节点,这里不用判断 s的数量,根据代码可知,这里至少存在一个节点
            var visit = s.Pop();
            if(k == 1)
            {
                // 第k最小元素
                return visit.val;
            }
            k--;

            // 访问右子树
            s.Push(visit.right);
        }
        return -1;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们可以按照序遍历的方式遍历二叉搜索树,得到一个有序的节点序列。接下来,通过二分查找的方法寻找第一个大于等于k的元素的位置,然后又能得到需要寻找的比k小的元素的范围。最后,我们可以返回这个范围的所有元素即可。以下是使用Python实现的代码示例: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def inorderTraversal(root): res = [] stack = [] curr = root while curr or stack: while curr: stack.append(curr) curr = curr.left curr = stack.pop() res.append(curr.val) curr = curr.right return res def findElementsLessThanK(root, k): if not root: return None nodes = inorderTraversal(root) l, r = 0, len(nodes) - 1 while l <= r: mid = (l + r) // 2 if nodes[mid] >= k: r = mid - 1 else: l = mid + 1 return nodes[:l] # 示例 root = TreeNode(5) root.left = TreeNode(3) root.right = TreeNode(7) root.left.left = TreeNode(2) root.left.right = TreeNode(4) root.right.left = TreeNode(6) root.right.right = TreeNode(8) k = 6 print(findElementsLessThanK(root, k)) # [2, 3, 4, 5] ``` 该代码,`inorderTraversal`函数实现了序遍历,返回节点升序排列的列表。`findElementsLessThanK`函数将序遍历的结果进行二分查找,获得第一个大于等于k的位置`l`,然后返回节点列表前`l`个元素,即为比k小的元素集合。最后,我们提供了一个示例,其我们构建了一个二叉搜索树,然后通过该函数找到了所有比k小的元素

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值