Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 이진 트리에서 두 노드 간 경로의 XOR 구하기

문제 소개

이 문제에서는 하나의 이진 트리와 그 트리에 속한 두 개의 노드가 주어집니다. 우리가 해야 할 일은 두 노드 사이의 경로에 놓인 모든 노드 값의 XOR을 계산해 출력하는 것입니다.

예시를 통해 문제를 자세히 살펴보겠습니다.

C++로 이진 트리에서 두 노드 간 경로의 XOR 구하기

위 트리에서 노드 2와 노드 3 사이 경로의 XOR을 구한다고 가정해 보겠습니다.

  • 노드 2에서 노드 3까지의 경로: 2 → 6 → 1 → 3
  • 따라서 계산해야 할 식은 2 ^ 6 ^ 1 ^ 3 입니다.

접근 방법

두 노드 사이의 경로를 일일이 찾아가는 대신, 루트에서 각 노드까지 이르는 경로의 XOR 누적값을 미리 계산해 두는 방식을 사용합니다. 루트에서 출발해 트리를 깊이 우선으로 순회하면서, 각 노드에 도달할 때까지 누적된 XOR 값을 해시 맵(unordered_map)에 노드 값과 함께 저장합니다.

이렇게 하면 XOR의 다음 성질을 활용할 수 있습니다.

  • 같은 값이 두 번 XOR되면 0이 되어 서로 상쇄됩니다. (a ^ a = 0)
  • 두 노드의 루트 경로가 공유하는 구간은 양쪽 경로에 모두 포함되므로, 두 누적 XOR 값을 서로 XOR하면 공통 구간이 자동으로 상쇄됩니다.

결국 path[node1] ^ path[node2] 한 번의 연산만으로 답을 구할 수 있습니다. 또한 순회 중 각 단계마다 지금까지의 XOR 결과에 현재 노드 값을 XOR하기만 하므로, 경로 전체를 따로 저장하지 않아도 되어 공간을 절약할 수 있습니다.

시간 복잡도는 트리를 한 번 순회하므로 O(N), 공간 복잡도는 각 노드의 XOR 값을 저장해야 하므로 O(N)입니다.

구현 예제

위 접근 방식을 C++로 구현한 프로그램은 다음과 같습니다.

#include <bits/stdc++.h>
using namespace std;
struct Node {
    int data;
    Node *left, *right;
};
struct Node* getNode(int data){
    struct Node* newNode = new Node;
    newNode->data = data;
    newNode->left = newNode->right = NULL;
    return newNode;
}
void pathStoD(Node* root, unordered_map<int, int>& path, int XOR){
    if (!root)
        return;
    path.insert(make_pair(root->data, XOR ^ root->data));
    XOR ^= root->data;
    if (root->left)
        pathStoD(root->left, path, XOR);
    if (root->right)
        pathStoD(root->right, path, XOR);
}
int findPathXOR(unordered_map<int, int> path, int node1, int node2){
    return path[node1] ^ path[node2];
}
int main(){
    struct Node* root = getNode(1);
    root->left = getNode(6);
    root->left->left = getNode(2);
    root->left->right = getNode(4);
    root->right = getNode(3);
    root->right->left = getNode(7);
    root->right->right = getNode(5);
    int XOR = 0;
    unordered_map<int, int> mp;
    int source = 2;
    int destination = 3;
    pathStoD(root, mp, XOR);
    cout<<"The XOR of all node from "<<source<<" to "<<destination<<" of the tree is : ";
    cout<<findPathXOR(mp, source, destination);
    return 0;
}

출력 결과

The XOR of all node from 2 to 3 of the tree is : 7

참고: 최소 공통 조상(LCA)의 상쇄

위 방식에서는 두 노드의 루트 경로에 공통으로 포함되는 최소 공통 조상(LCA) 노드 역시 두 번 XOR되어 결과에서 자연스럽게 제외됩니다. 예제에서 노드 2와 노드 3의 LCA는 루트 노드 1이므로, 프로그램의 출력값 7은 (2 ^ 6) ^ (3), 즉 LCA를 제외한 경로 노드들의 XOR에 해당합니다. 만약 LCA 노드를 결과에 반드시 포함해야 한다면 path[node1] ^ path[node2] ^ LCA값을 추가로 계산해 주면 됩니다.