首页 > 试题广场 >

距离是K的二叉树节点

[编程题]距离是K的二叉树节点
  • 热度指数:612 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个二叉树的根节点 root ,和一个目标节点的值 target ,和一个目标距离 k ,请你找出二叉树上所有与 target 距离是 k 的节点的值。



数据范围:二叉树的节点数满足 ,节点上的值在范围 [0,n) 内,每个节点的值各不相同。
示例1

输入

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

输出

[1,8,2]

说明:本题目包含复杂数据结构TreeNode,点此查看相关信息
# -*- coding: utf-8 -*-


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class BT:
    def __init__(self):
        self.root = None

    def levelOrderToBT(self, nums):  # 层序遍历构造二叉树
        n = len(nums)

        if n > 0:
            self.root = TreeNode(nums[0])
            queue, idx = [self.root], 1

            while queue and idx < n:
                node = queue.pop(0)
                node.left = TreeNode(nums[idx]) if nums[idx] != None else None
                if node.left:
                    queue.append(node.left)
                node.right = TreeNode(nums[idx + 1]) \
                    if idx + 1 < n and nums[idx + 1] != None else None
                if node.right:
                    queue.append(node.right)
                idx += 2

        return self.root

    @staticmethod
    def levelOrder(root):  # 二叉树的层序遍历
        if not root:
            return []

        queue, res = [root], []
        while queue:
            node = queue.pop(0)
            if node:
                res.append(node.val)
                queue.append(node.left)
                queue.append(node.right)
            else:
                res.append(None)
        while res and res[-1] == None:
            res.pop()

        return res


#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param root TreeNode类
# @param target int整型
# @param k int整型
# @return int整型一维数组
#
class Solution:
    """
    题目:
        https://www.nowcoder.com/practice/e280b9b5aabd42c9b36831e522485622?tpId=196&tqId=40501&rp=1&ru=/exam/oj&qru=/exam/oj&sourceUrl=%2Fexam%2Foj%3FjudgeStatus%3D3%26page%3D1%26pageSize%3D50%26search%3D%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D196&difficulty=undefined&judgeStatus=3&tags=&title=
    参考:
        大神:姐姐的遮阳伞
    算法:
        1. 一次先序遍历二叉树,在寻找targetNode的同时,建立哈希表nodeMap,键:当前节点,值:该节点的父亲节点
        2. 对于距离为k的分析:
            a. 我们可以从targetNode出发,在其左右子树上寻找距离为k的节点
            b. 也可以通过哈希表,向上回溯到父亲节点进行搜索,只不过搜索的过程中,我们需要修改距离k:
                i) 回溯到targetNode的parent节点parentNode,若targetNode为parentNode的左孩子,那么我们从parentNode.right子树上寻找与根节点距离为k-2的节点;否则,若targetNode为parentNode的右孩子,那么我们从parentNode.left子树上寻找与根节点距离为k-2的节点
                ii) 再回溯到parentNode的父亲节点。继续搜索
                ...
                直到回溯到根节点或者k小于0为止
    复杂度:
        时间复杂度:O(N + kM) = O(k*N),k为距离,M为每次搜索的平均节点数,N为二叉树的节点数
        空间复杂度:O(H), H为树的高度
    """

    def distanceKnodes(self, root, target, k):
        # write code here
        def helper(root):
            if root:
                if root.val == target:
                    self.targetNode = root
                if root.left:
                    nodeMap[root.left.val] = root
                if root.right:
                    nodeMap[root.right.val] = root
                helper(root.left)
                helper(root.right)

        def findAnsFromChild(node, k):  # 从node的左右子树中,寻找与node距离为k的节点
            if node:
                if k == 0:
                    if node.val != target:  # 搜索结果,剔除target
                        res.append(node.val)
                    return
                findAnsFromChild(node.left, k - 1)  # 递归搜索左子树
                findAnsFromChild(node.right, k - 1)  # 递归搜索右子树

        nodeMap, self.targetNode = {root.val: None}, None  # nodeMap记录节点node与其父亲节点的映射关系,targetNode为目标节点
        helper(root)

        res, startNode = [], self.targetNode
        findAnsFromChild(startNode, k)

        k -= 1  # 回溯到targetNode的父亲节点parentNode
        while k >= 0:
            parentNode = nodeMap[startNode.val]
            if not parentNode:  # 所有的父亲节点已经搜索完毕
                break

            if k == 0:  # 当回溯到根节点的距离恰好是k时,就无须探索了,因为再回溯,必然使得距离大于k
                res.append(parentNode.val)
                break

            if startNode == parentNode.left and k - 1 >= 0:  # startNode为parentNode的左孩子,就去parentNode的右子树搜索
                findAnsFromChild(parentNode.right, k - 1)
            if startNode == parentNode.right and k - 1 >= 0:  # startNode为parentNode的右孩子,就去parentNode的左子树搜索
                findAnsFromChild(parentNode.left, k - 1)

            startNode = parentNode  # 回溯到父亲节点
            k -= 1  # 距离-1

        return res


if __name__ == "__main__":
    sol = Solution()

    nums, target, k = [3, 5, 2, 4, 6, 0, 7, 1, 8], 5, 2

    # nums, target, k = [1, 2, 3, 4], 2, 1

    bt = BT()
    bt1 = bt.levelOrderToBT(nums)
    print BT.levelOrder(bt1)

    res = sol.distanceKnodes(bt1, target, k)
    print res

发表于 2022-07-06 09:44:56 回复(0)

问题信息

难度:
1条回答 1767浏览

热门推荐

通过挑战的用户

查看代码