还考虑空节点找到二叉树的两个节点之间的水平距离?

时间:2020-05-10 13:55:27

标签: python algorithm data-structures tree time-complexity

我有一个二叉树,其中每个节点都有唯一的整数。我想找到位于同一层的两个节点之间的水平距离。 某些节点可能没有子节点或子树,但要计算距离,我们还需要考虑那些空节点。就像在附加的二叉树中,Distance(7,1)= 3和Distance(9,4)= 6。 为此,我尝试了以下步骤:

  1. 将现有树转换为完整的二叉树。向不存在子子树或满足完整二叉树条件的节点的节点添加空节点。
  2. 使用广度优先搜索算法遍历树,并将遍历遍历存储在字典中。
  3. 获取用户输入的值,例如级别,first_node,second_node,并在对树中的所有节点进行验证后给出它们之间的距离。

通过执行上述步骤,我得到了解决方案,但是它花费了 O(N ^ 2)的时间复杂度。要使二叉树变成完整的二叉树需要 O(N ^ 2),而使用BFS遍历则需要 O(N ^ 2 )时间复杂度。

还有其他方法可以解决此问题,以便仅在不执行完整的二叉树转换过程的情况下进行遍历吗?

我的代码实现

from pprint import pprint
class Node:
    def __init__(self, data):
        self.data = data
        self.right = None
        self.left = None

    @property
    def maxDepth(self):  # get the height of tree
        depth = 0
        if self.left:  depth = self.left.maxDepth + 1
        if self.right: depth = max(depth, self.left.maxDepth + 1)
        return depth

    def expandToDepth(self, depth=None):  # full binary tree conversion method
        if depth is None: depth = self.maxDepth
        if not depth: return
        if not self.left:  self.left = Node(None)
        if not self.right: self.right = Node(None)
        self.left.expandToDepth(depth - 1)
        self.right.expandToDepth(depth - 1)


d = {}


def traverse_dfs(root):  # traverse the whole tree with BFS algo
    h = root.maxDepth + 1
    for i in range(1, h + 1):
        level_traverse(root, i, i)


def level_traverse(root, level, original_level):  # traverse the nodes at particular level
    if root is None:
        return
    if level == 1:
        if d.get(original_level):
            d[original_level].append(root.data)
        else:
            d[original_level] = [root.data]
    elif level > 1:
        level_traverse(root.left, level - 1, original_level)
        level_traverse(root.right, level - 1, original_level)


root = Node(5)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(7)
root.left.left.left = Node(9)
root.right.right = Node(1)
root.right.right.right = Node(6)
root.right.right.left = Node(4)

root.expandToDepth()  # convert normal tree to full binary tree

traverse_dfs(root)    # BFS traversal and stor the level wise traversal in dictionary d.

pprint(d)

level = int(input("Enter level: "))
first_node, second_node = map(int, input("Enter two nodes separated with space: ").split())

print("Getting horizontal distance between given nodes lies on the same level")
if first_node is None or second_node is None:
    print("None type nodes are invalid")
    exit()
if d.get(level):
    if first_node in d[level] and second_node in d[level]:
        distance = abs(d[level].index(first_node) - d[level].index(second_node))
        print(distance)
    else:
        print("Distance invalid")
else:
    print("Invalid level")

输出:

{1: [5],
 2: [2, 3],
 3: [7, None, None, 1],
 4: [9, None, None, None, None, None, 4, 6]}
Enter level: 3
Enter two nodes separated with space: 7 1
Getting horizontal distance between given nodes lies on the same level
3

Binary tree

1 个答案:

答案 0 :(得分:1)

实际上,添加缺少的节点效率很低。您可以在没有这些距离的情况下得出此距离。想象一下,两个选定节点的最低共同祖先,以及从那里到两个节点的路径如何给出有关可能可能在那里的节点的线索。

例如,对于输入9和4,公共祖先是根。从根到第一个节点的路径是LLL(左-左-左)。另一条路径是RRL。

现在,让我们开始第一个路径。想象是LLR而不是LLL:会使距离缩短1。或者想象它是LRL而不是LLL:会使距离缩短2。实际上,您会注意到这种单一路径的变化会产生影响到2的幂的距离。幂就是您离节点向上的距离。

因此,...您可以将这些路径创建为二进制数。在示例中:000和110。 现在以二进制表示形式将它们彼此相减:您得到6。这确实是距离。

所以您的代码可能是:

class Node:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

def dfs(root, d={}, path=""):
    if root:
        d[root.data] = path
        dfs(root.left, d, path+"0")
        dfs(root.right, d, path+"1")
    return d

root = Node(5)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(7)
root.left.left.left = Node(9)
root.right.right = Node(1)
root.right.right.right = Node(6)
root.right.right.left = Node(4)

# create a dictionary of <nodevalue, path>
d = dfs(root)

val1, val2 = map(int, input("Enter two nodes separated with space: ").split())

# convert the numbers to the corresponding paths:
node1 = d.get(val1, None)
node2 = d.get(val2, None)

# check whether these nodes actually exist
if node1 is None or node2 is None:
    print("At least one value is invalid or not found")
    exit()

# If the paths have different lengths, the nodes are not on the same level
if len(node1) != len(node2):
    print("Nodes are not on the same level")
    exit()

# Use the magic of binary numbers:
dist = abs(int(node1, 2) - int(node2, 2))
print(dist)
相关问题