Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python으로 두 이진 트리의 모든 레벨이 아나그램인지 확인하는 방법

두 개의 이진 트리(binary tree)가 주어졌을 때, 첫 번째 트리의 각 레벨이 두 번째 트리의 같은 레벨과 아나그램(anagram) 관계인지 확인하는 문제를 살펴보겠습니다. 여기서 아나그램이란 구성 요소는 같지만 순서만 다른 경우를 의미합니다. 모든 레벨이 아나그램이라면 True를, 하나라도 다르면 False를 반환하면 됩니다.

예를 들어 다음과 같은 두 트리가 입력으로 주어진다면,

Python으로 두 이진 트리의 모든 레벨이 아나그램인지 확인하는 방법

출력 결과는 True가 됩니다.

문제 해결 접근 방식

이 문제는 레벨 순회(level order traversal)와 큐(queue)를 활용하면 효율적으로 해결할 수 있습니다. 핵심 아이디어는 두 트리를 동시에 레벨 단위로 탐색하면서, 각 레벨의 노드 값들을 정렬한 뒤 서로 일치하는지 비교하는 것입니다.

알고리즘 단계

  • tree_1은 첫 번째 트리의 루트 노드, tree_2는 두 번째 트리의 루트 노드입니다.
  • 두 트리가 모두 null(빈 트리)이면 True를 반환합니다.
  • 둘 중 하나만 null이면 구조가 다르므로 False를 반환합니다.
  • 두 개의 큐 queue1, queue2를 생성하고 각각 루트 노드를 삽입합니다.
  • 반복문 안에서 다음을 수행합니다:
    • 각 큐의 현재 크기(size1, size2)를 확인합니다.
    • 크기가 다르면 해당 레벨의 노드 수가 다른 것이므로 False를 반환합니다.
    • 크기가 0이면 모든 레벨 탐색이 끝난 것이므로 반복을 종료합니다.
    • 현재 레벨의 노드 값을 저장할 리스트 curr_level1, curr_level2를 생성합니다.
    • 큐에서 노드를 하나씩 꺼내며 자식 노드를 큐에 추가하고, 노드 값을 현재 레벨 리스트에 기록합니다.
    • 한 레벨의 순회가 끝나면 두 리스트를 각각 정렬한 후 비교합니다.
    • 정렬된 두 리스트가 다르면 False를 반환합니다.
  • 모든 레벨이 일치하면 최종적으로 True를 반환합니다.

Python 구현 예제

아래 코드를 통해 실제 동작을 더 잘 이해할 수 있습니다.

def make_tree(elements):
    tree = tree_node(elements[0])
    for element in elements[1:]:
        insert_value(tree, element)
    return tree

def insert_value(temp, value):
    que = []
    que.append(temp)
    while (len(que)):
        temp = que[0]
        que.pop(0)
        if (not temp.left):
            if value is not None:
                temp.left = tree_node(value)
            else:
                temp.left = tree_node(0)
            break
        else:
            que.append(temp.left)
        if (not temp.right):
            if value is not None:
                temp.right = tree_node(value)
            else:
                temp.right = tree_node(0)
            break
        else:
            que.append(temp.right)

class tree_node:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

def solve(tree_1, tree_2):
    if (tree_1 == None and tree_2 == None):
        return True
    if (tree_1 == None or tree_2 == None):
        return False
    queue1 = []
    queue2 = []
    queue1.append(tree_1)
    queue2.append(tree_2)
    while (1):
        size1 = len(queue1)
        size2 = len(queue2)
        if (size1 != size2):
            return False
        if (size1 == 0):
            break
        curr_level1 = []
        curr_level2 = []
        while (size1 > 0):
            node1 = queue1[0]
            queue1.pop(0)
            if (node1.left != None):
                queue1.append(node1.left)
            if (node1.right != None):
                queue1.append(node1.right)
            size1 -= 1
            node2 = queue2[0]
            queue2.pop(0)
            if (node2.left != None):
                queue2.append(node2.left)
            if (node2.right != None):
                queue2.append(node2.right)
            curr_level1.append(node1.value)
            curr_level2.append(node2.value)
        curr_level1.sort()
        curr_level2.sort()
        if (curr_level1 != curr_level2):
            return False
    return True

tree_1 = make_tree([5, 6, 7, 9, 8])
tree_2 = make_tree([5, 7, 6, 8, 9])
print(solve(tree_1, tree_2))

입력

[5, 6, 7, 9, 8], [5, 7, 6, 8, 9]

출력

True

코드 설명 및 시간 복잡도

make_tree 함수는 리스트 값을 순서대로 트리에 삽입하여 이진 트리를 생성하고, solve 함수는 앞서 설명한 알고리즘대로 두 트리를 레벨 단위로 비교합니다. 위 예제에서 첫 번째 트리의 루트 자식들은 [6, 7], 두 번째 트리의 루트 자식들은 [7, 6]으로 정렬하면 동일하므로 아나그램 관계입니다. 그 아래 레벨도 마찬가지로 [9, 8][8, 9]로 일치하기 때문에 최종 결과는 True입니다.

시간 복잡도는 각 노드를 한 번씩 방문하고 레벨별 정렬이 수행되므로 O(n log n)입니다. 여기서 n은 트리의 전체 노드 수입니다. 공간 복잡도는 큐와 레벨 리스트 저장에 O(n)이 필요합니다.