【剑指offer】JZ54 二叉搜索树的第k个节点

1 问题

数据范围:
0≤n≤1000,0≤k≤1000,树上每个结点的值满足0≤val≤1000
进阶:空间复杂度 O(n),时间复杂度 O(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

2 答案

自己写的,回溯算法

class Solution:
    def KthNode(self , proot: TreeNode, k: int) -> int:
        res = []
        self.dfs(proot, res)
        return res[k-1] if k-1 >= 0 and k-1 <= len(res) - 1 else -1
        
    def dfs(self, proot, res):
        if not proot:
            return 
        # if not proot.left and not proot.right:
        #     return 
        # 不能这样写,因为最后一个叶节点不会遍历
        self.dfs(proot.left, res)
        res.append(proot.val)
        self.dfs(proot.right, res)

在这里插入图片描述
官方解

  1. 递归中序遍历

根据二叉搜索树的性质,左子树的元素都小于根节点,右子树的元素都大于根节点。因此它的中序遍历(左中右)序列正好是由小到大的次序,因此我们可以尝试递归中序遍历,也就是从最小的一个节点开始,找到k个就是我们要找的目标。

  • step 1:设置全局变量count记录遍历了多少个节点,res记录第k个节点。
  • step 2:另写一函数进行递归中序遍历,当节点为空或者超过k时,结束递归,返回。
  • step 3:优先访问左子树,再访问根节点,访问时统计数字,等于k则找到。
  • step 4:最后访问右子树。
class Solution:
    def __init__(self):
        self.res = None
        self.count = 0
        
    def midOrder(self, root, k):
        if not root or self.count > k:
            return 
        self.midOrder(root.left, k)
        self.count+=1
        if self.count == k:
            self.res = root # 不在这里return,在上面return
        self.midOrder(root.right, k)

    def KthNode(self , proot: TreeNode, k: int) -> int:
        self.midOrder(proot, k)
        if self.res:
            return self.res.val
        else:
            return -1
  1. 非递归中序遍历,栈

递归实际上就是一种先进后出的栈结构,因此能用递归进行的中序遍历,非递归(栈)也可以实现,还是需要记录遍历到第k位即截止。

  • step 1:用栈记录当前节点,不断往左深入,直到左边子树为空。
  • step 2:再弹出栈顶(即为当前子树的父节点),访问该节点,同时计数。
  • step 3:然后再访问其右子树,其中每棵子树都遵循左中右的次序。
  • step 4:直到第k个节点返回,如果遍历结束也没找到,则返回-1.
class Solution:
    def KthNode(self , proot: TreeNode, k: int) -> int:
        if not proot:
            return -1
        count = 0
        p = None
        s = []
        while len(s) != 0 or proot is not None:
            while proot is not None:
                s.append(proot)
                proot = proot.left
            p = s[-1]
            s.pop()
            count += 1
            if count == k:
                return p.val
            proot = p.right
        return -1

https://www.nowcoder.com/share/jump/9318638301699766385619

也可以用颜色标记迭代法

class Solution:
    def KthNode(self , proot: TreeNode, k: int) -> int:
        WhITE, GRAY = 0, 1
        count = 0
        stack = [(WhITE, proot)]
        while stack:
            color, node = stack.pop()
            if node is None: continue
            if color == WhITE:
                stack.append((WhITE, node.right))
                stack.append((GRAY, node))
                stack.append((WhITE, node.left))
            else:
                # 这里才是真正有效遍历节点的地方
                count += 1
                if count == k:
                    return node.val
        return -1

https://blog.csdn.net/CSDNLHCC/article/details/134019651?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169976648016800213014996%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=169976648016800213014996&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-134019651-null-null.nonecase&utm_term=%E4%BA%8C%E5%8F%89%E6%A0%91&spm=1018.2226.3001.4450

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LouHerGetUp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值