문제 개요
이진 트리가 하나 주어지고, 우리는 트리의 노드들에 카메라를 설치하려고 합니다. 특정 노드에 설치된 카메라는 자기 자신, 부모 노드, 그리고 직계 자식 노드를 감시할 수 있습니다. 이때 트리의 모든 노드를 감시하기 위해 필요한 최소 카메라 개수를 구하는 것이 목표입니다.
예를 들어 입력이 다음과 같다면 −

출력은 1이 됩니다. 카메라 한 대만으로도 트리의 모든 노드를 감시할 수 있기 때문입니다.
해결 접근 방법: 그리디 + 후위 순회
이 문제는 그리디(Greedy) 전략과 후위 순회(Post-order Traversal)를 조합하면 효율적으로 해결할 수 있습니다. 핵심 아이디어는 다음과 같습니다.
카메라를 리프(leaf) 노드에 설치하는 것보다 리프의 부모 노드에 설치하는 것이 항상 더 유리합니다. 부모에 카메라를 두면 자기 자신과 두 자식을 동시에 커버할 수 있기 때문입니다. 따라서 트리를 아래에서 위로(후위 순회) 탐색하면서, 자식 중 커버되지 않은 노드가 있으면 현재 노드에 카메라를 설치하는 방식으로 진행합니다.
알고리즘 단계
TreeNode타입의 집합(set)covered를 정의합니다. (TreeNode는 left, right, val 필드를 가집니다)solve(node, parent)함수를 정의합니다.node가 NULL이면 그대로 반환합니다.solve(node->left, node)와solve(node->right, node)를 재귀 호출하여 자식부터 처리합니다.- 다음 조건 중 하나라도 만족하면 현재 노드에 카메라를 설치합니다:
- 부모가 NULL인데(루트 노드) 자신이 아직 커버되지 않은 경우
- 왼쪽 자식이 커버되지 않은 경우
- 오른쪽 자식이 커버되지 않은 경우
- 카메라를 설치하면 답(ans)을 1 증가시키고, 현재 노드와 왼쪽 자식, 오른쪽 자식, 부모 노드를
covered에 추가합니다.
메인 메서드 처리 흐름
ans := 0으로 초기화합니다.covered에 NULL을 미리 삽입합니다. (NULL 자식은 이미 커버된 것으로 간주하기 위함입니다)solve(root, NULL)을 호출합니다.ans를 반환합니다.
구현 예제 코드
아래 구현을 통해 더 잘 이해해 보겠습니다 −
#include <bits/stdc++.h>
using namespace std;
class TreeNode{
public:
int val;
TreeNode *left, *right;
TreeNode(int data){
val = data;
left = NULL;
right = NULL;
}
};
class Solution {
public:
set<TreeNode*> covered;
int ans;
int minCameraCover(TreeNode* root){
covered.clear();
ans = 0;
covered.insert(NULL);
solve(root, NULL);
return ans;
}
void solve(TreeNode* node, TreeNode* parent){
if (!node)
return;
solve(node->left, node);
solve(node->right, node);
if ((parent == NULL && covered.find(node) == covered.end())
|| covered.find(node->left) == covered.end() || covered.find(node-
>right) == covered.end()) {
ans++;
covered.insert(node);
covered.insert(node->left);
covered.insert(node->right);
covered.insert(parent);
}
}
};
main(){
Solution ob;
TreeNode *root = new TreeNode(1);
root->left = new TreeNode(1);
root->left->left = new TreeNode(1); root->left->right = new
TreeNode(1);
cout << (ob.minCameraCover(root));
}입력
[1,1,NULL,1,1]
출력
1
복잡도 분석
모든 노드를 한 번씩 방문하므로 시간 복잡도는 노드 수를 N이라 할 때 O(N log N)입니다(집합 연산에 로그 계수가 추가됩니다). 공간 복잡도는 재귀 호출 스택과 covered 집합 때문에 O(N)입니다. 만약 상태 값을 반환하는 방식으로 최적화하면 O(N) 시간에 해결할 수도 있습니다.