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

Python으로 트리 노드의 K번째 조상 찾는 프로그램


n개의 노드(0부터 n-1까지 번호가 매겨짐)로 구성된 트리가 있다고 가정해 보겠습니다. 트리는 parent 배열로 주어지며, parent[i]는 노드 i의 부모 노드를 나타냅니다. 트리의 루트는 0번 노드입니다. 우리가 해야 할 일은 주어진 노드의 k번째 조상을 찾는 것이고, 만약 해당 조상이 존재하지 않는다면 -1을 반환하면 됩니다.

예를 들어 입력이 다음과 같다고 해보겠습니다.

Python으로 트리 노드의 K번째 조상 찾는 프로그램

그렇다면 출력은 2가 됩니다. 노드 6의 첫 번째 조상은 5이고, 두 번째 조상은 2이기 때문입니다.

문제 해결 접근 방식

이 문제는 단순히 k번 반복하며 부모를 따라 올라가는 방법(O(k))보다 더 효율적으로 풀 수 있습니다. 핵심 아이디어는 분할 정복(Divide and Conquer)을 활용하는 것입니다.

  • solve() 함수를 정의합니다. 이 함수는 parent, node, k 세 개의 인자를 받습니다.

  • node가 -1이라면(루트 위로 더 올라갈 수 없다면) -1을 반환합니다.

  • k가 1이라면 바로 parent[node]를 반환합니다.

  • k와 (k-1)의 비트 AND 연산 결과가 0이라면, 즉 k가 2의 거듭제곱이라면 문제를 절반으로 나눕니다.
    → solve(parent, solve(parent, node, k/2), k/2)를 반환합니다.

  • 그 외의 경우에는 k에서 최상위 비트(msb)만큼 떼어낸 뒤 처리합니다.
    → msb = 2^(k의 비트 길이 - 1)로 계산하고, solve(parent, solve(parent, node, k-msb), msb)를 반환합니다.

이 방식은 매 단계마다 k가 절반으로 줄어들거나 최상위 비트가 제거되므로, 전체 시간 복잡도가 O(log k)로 크게 개선됩니다.

구현 예시

아래 구현을 통해 더 잘 이해해 보겠습니다.

def solve(parent, node, k):
   if node == -1:
      return -1
   elif k == 1:
      return parent[node]
   elif not (k & k-1):
      return solve(parent, solve(parent, node, k >> 1), k >> 1)
   else:
      msb = 1 << (k.bit_length()-1)
      return solve(parent, solve(parent, node, k-msb), msb)

parent = [-1,0,0,1,2,2,5,5]
node = 6
k = 2
print(solve(parent, node, k))

입력

parent = [-1,0,0,1,2,2,5,5], node = 6, k = 2

출력

2