71. 최소 공통 조상 (LCA, Lowest Common Ancestor)

핵심 인사이트 (3줄 요약)

  1. 본질: 최소 공통 조상(Lowest Common Ancestor, LCA)은 두 노드의 공통 조상 중 가장 가까운(깊이가深い) 조상을 찾는 문제이다.
  2. 가치: 트리에서 두 노드 사이의最短경로 찾기, 근접 조상 관계 确定 등 다양한 문제의基礎이 된다.
  3. 융합: 네트워크 분석, 계층적 데이터 查询,最小공통조상問題의 변형 등 다양한領域에서 활용된다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

최소 공통 조상(Lowest Common Ancestor, LCA)은 rooted tree(루트 트리)에서 두 노드 u와 v의 공통 조상 중에서 루트에서 가장 멀리(깊이가深い) 있는 조상을 찾는問題이다. 공통 조상이란 u와 v 모두의 조상인 노드를 의미하며, 최소 공통 조상은 그러한 노드들 중에서 두 노드에 가장 가까운 것이다.

LCA가 중요한 이유는 트리 기반 문제의 기본 도구이기 때문이다. 두 노드 사이의最短경로 = LCA를 통한 경로로 표현할 수 있다. u에서 v로的最短경로는 u → LCA(u, v) → v로 표현된다.

LCA는 系譜学에서도 중요한概念이다.两个人의共同祖先을 찾고, 그 중 가장 가까운(최근)에 해당하는 것이 系譜에서 "공통 조상"이 된다.

[LCA 예시]

┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  [루트 트리]                                                  │
│  ────────────────────────────────────────────                │
│                                                              │
│                         A(루트)                               │
│                       / | \                                  │
│                      B  C  D                                 │
│                    / \    / \                                │
│                   E   F  G   H                               │
│                  / \                │                        │
│                 I   J               │ (I의 조상: I, E, B, A) │
│                                      │ (J의 조상: J, E, B, A) │
│                                   (LCA(I,J) = E)             │
│                                                              │
│  LCA(I, J) = E                                               │
│  - E는 I과 J의 공통 조상이다 (I과 J의 조상 중 E가 있다)       │
│  - E는 가장 깊은(루트에서 멀리 있는) 공통 조상이다            │
│                                                              │
│  [다른 예시]                                                 │
│  ────────────────────────────────────────────                │
│  LCA(E, F) = B (B가 E과 F의 조상 중 가장 깊다)              │
│  LCA(B, C) = A (B와 C의 공통 조상은 A뿐)                     │
│  LCA(A, E) = A (A는 E의 조상이면서 루트)                     │
│                                                              │
└──────────────────────────────────────────────────────────────┘
  • 관찰: LCA는 항상 유일하게 존재한다(루트 트리에서).
  • 원인: 루트를 제외한 모든 노드는 반드시 하나의 부모를 가지므로, 두 노드의 조상 집합의 교집합은 비어있지 않다.
  • 결과: 모든 노드는 루트까지의 유일한 경로를 가지므로, 공통 조상이 반드시 존재한다.
  • 판단: LCA를 찾는 알고리즘의 효율성이 중요한問題이다.

📢 섹션 요약 비유: LCA는 家族 系譜와 같습니다. 두명의堂兄弟의最小公祖先을 찾으면, 공통된조상中最接近な者を探すことになる。例气면, "철수"와 "영희"의 最近共通祖先이 "할아버지"라면, 祖父以下の系統ではなく、祖父以上の系統で交わっている最も近い节点がそれに当たる.


Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

LCA를 찾는 주요 알고리즘들을 살펴보자.

Naive 방법: 각 노드의 조상들을 표시하고, 다른 노드의 조상들과 비교한다. 시간 복잡도 O(N), 공간 복잡도 O(N).

DFS + 부모 포인터: 두 노드에서 루트까지의 경로를 각각 찾고, 경로에서 첫 번째 공통 노드를 찾는다. 시간 복잡도 O(N), 공간 복잡도 O(H).

Binary Lifting:预处理로 각 노드의 2^k 조상을 저장한다. Find 시 먼저 깊이를 맞추고, 동시에 위로 올라가며 LCA를 찾는다.预处理 O(N log N), 각 Query O(log N).

RMQ 기반 방법: Euler Tour과 Sparse Table을 利用하여 O(1) Query를 달성한다. 많은 수의 Query가 있을 때 유용하다.

[LCA 알고리즘 상세]

┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  [Binary Lifting 방법]                                        │
│  ────────────────────────────────────────────                │
│                                                              │
│  //预处理: 각 노드의 2^k 조상 저장                              │
│  MAX_LOG = ceil(log2(N))                                     │
│                                                              │
│  parent[k][v] = v의 2^k 번째 조상                             │
│  depth[v] = v의 깊이 (루트에서 v까지의 거리)                  │
│                                                              │
│  // 2^k 조상 계산                                             │
│  parent[0][v] = v의 직접 부모                                 │
│  parent[k][v] = parent[k-1][parent[k-1][v]]                  │
│                                                              │
│  // LCA 찾기                                                 │
│  function lca(u, v):                                        │
│      // 1. 깊이 맞추기                                         │
│      if depth[u] < depth[v]:                                 │
│          swap(u, v)                                          │
│                                                              │
│      // u을 v와 같은 깊이로 올리기                             │
│      diff = depth[u] - depth[v]                              │
│      for k in range(MAX_LOG):                                │
│          if diff & (1 << k):                                 │
│              u = parent[k][u]                                │
│                                                              │
│      // 2. 동시에 올려가며 LCA 찾기                            │
│      if u == v:                                              │
│          return u                                             │
│                                                              │
│      for k in range(MAX_LOG - 1, -1, -1):                    │
│          if parent[k][u] != parent[k][v]:                    │
│              u = parent[k][u]                                │
│              v = parent[k][v]                                │
│                                                              │
│      return parent[0][u]  // 바로 위 조상이 LCA              │
│                                                              │
│  [시간 복잡도]                                                │
│  ────────────────────────────────────────────                │
│  preprocessing: O(N log N)                                    │
│  each query: O(log N)                                        │
│                                                              │
└──────────────────────────────────────────────────────────────┘
  • 관찰: Binary Lifting은 2의 거듭제곱으로 조상들을 점프한다.
  • 원인: 모든 수를 2진수로 표현할 수 있듯이, 모든 깊이 차이도 2의 거듭제곱 합으로 표현할 수 있기 때문이다.
  • 결과: 깊이 차이만큼 정확하게 올려서 두 노드를 같은 깊이로 만들 수 있다.
  • 판단: Query 수가 많으면 Binary Lifting이 효율적이다.

📢 섹션 요약 비유: Binary Lifting은 계단을 오르는策略와 같습니다. 1칸, 2칸, 4칸, 8칸... 씩 점프할 수 있다면, 어떤 높이差든 2의 거듭제곱 조합으로 표현할 수 있어 가장 효율적으로高度を合わせることができる.


Ⅲ. 구현 및 실무 응용 (Implementation & Practice)

LCA의 실무 적용은 다음과 같다. 네트워크 라우팅: 라우터들의 계층적構造에서 두 라우터의最近接共通祖先(LCA)를 찾아 경로를 결정한다. 계층적 데이터 Query: 조직도, 카테고리 분류 등 계층적 데이터에서 두 항목의最近接共通항목을 찾는다.

응용: 노드 사이 거리 계산: 두 노드 u, v 사이의 거리는 dist(u, v) = dist(u, lca) + dist(v, lca)로 계산할 수 있다. 응용: 부분 트리 Query: 특정 노드의 하위 트리에 속하는 노드들 사이의 LCA는 항상 해당 노드이다.

[LCA 실무 활용]

┌──────────────────────────────────────────────────────────────┐
│                                                              │
│  [두 노드 사이 거리 계산]                                      │
│  ────────────────────────────────────────────                │
│                                                              │
│  거리 = depth[u] + depth[v] - 2 * depth[lca(u, v)]          │
│                                                              │
│  예시:                                                       │
│  depth[I] = 3, depth[J] = 3, depth[E] = 2                    │
│  거리(I, J) = 3 + 3 - 2*2 = 2                               │
│  (I → E → J 경로, 2칸)                                      │
│                                                              │
│  [계층적 카테고리 분류]                                        │
│  ────────────────────────────────────────────                │
│                                                              │
│  카테고리 트리:                                               │
│  Electronics                                                  │
│    ├── Computers                                              │
│    │   ├── Laptops                                           │
│    │   └── Desktops                                          │
│    └── Phones                                                │
│        ├── Smartphones                                       │
│        └── Feature phones                                    │
│                                                              │
│  "Laptop"과 "Smartphone"의 LCA = Electronics                 │
│  → 서로 다른 주分类이지만 같은 상위 카테고grin 소속             │
│                                                              │
│  [IRT (Item Response Theory) - 교육测验]                     │
│  ────────────────────────────────────────────                │
│  시험 문항들의 능력치分层에서, 두 문항의共通能力 수준 찾기     │
│                                                              │
└──────────────────────────────────────────────────────────────┘

📢 섹션 요약 비유: LCA 실무 활용은 都市 계획과 같습니다. 두 地区中心街の最近接共通繁華街を 찾아、その2つ地区中心街への道计算出により、最短時間で2つか所赴くことができる。のように、LCAは都市間の最直通経路を求める際に応用される。


Ⅳ. 품질 관리 및 테스트 (Quality & Testing)

LCA의 품질 관리에서 가장 중요한 것은 루트 설정깊이 계산이다.

품질 관리 체크리스트: 트리가 rooted tree인지 확인해야 한다(모든 노드에 부모가 하나). 루트가 올바르게 설정되어야 depth 계산이 정확하다. parent 배열이 정확한지 확인해야 한다.

📢 섹션 요약 비유: LCA 품질 관리는 등산길 지도 작성과 같습니다. 모든 갈림길에서 올바른 방향(부모 노드)으로 이어지는지 확인하고, 각 지점까지の垂直距離を正確に測定することで、2つの地点間の最短距離、正確に計算できる。


LCA의 최신 동향은 더 빠른 Query동적 트리 처리와 관련되어 있다. Link-Cut Tree: 동적으로 트리가 변할 때 LCA를 지원하는 자료구조. Euler Tour + RMQ: O(1) Query를 달성하지만预处理이 복잡하다.

LCA는 "트리 기반 문제의 핵심 도구"로서, 다양한 그래프 알고리즘의 기초가 된다.

📢 섹션 요약 비유: LCA의 발전은 **우주 탐사 로프트*와 같습니다。初期에는 두 천체 사이의最短距離を計算するのが面倒だったが、より先进的な算法により、两个的任何任意两天体間の共通祖先を即座に 찾을 수 있어ようになった。


핵심 인사이트 ASCII 다이어그램 (Concept Map)

[최소 공통 조상 (LCA) 핵심 개념 맵]

         ┌─────────────────────────────────┐
         │   최소 공통 조상 (LCA, Lowest Common Ancestor)   │
         └────────────────┬────────────────┘
                          │
      ┌───────────────────┼───────────────────┐
      │                   │                    │
      ▼                   ▼                    ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  핵심 개념    │  │  알고리즘     │  │   실무 활용   │
│ 공통 조상     │  │ Binary Lift │  │  Use Cases  │
├──────────────┤  ├──────────────┤  ├──────────────┤
│ 가장 가까운   │  │预处理O(NlogN)│  │ 네트워크 라우팅│
│ (깊이 가장    │  │ Query O(logN)│  │ 계층적 데이터  │
│ 깊은)        │  │             │  │ 거리 계산     │
└──────────────┘  └──────────────┘  └──────────────┘

참고

  • 모든 약어는 반드시 전체 명칭과 함께 표기
  • 일어/중국어 절대 사용 금지
  • 각 섹션 끝에 📢 요약 비유 반드시 추가
  • 최소 800자/파일
  • 파일명: 01_, 02_... 형식