트리가 주어지고 각 노드의 값은 정수로 이루어져 있다.
트리는 두 가지 조건에 따라 홀짝 트리로 구분된다:
홀짝 트리:
역 홀짝 트리:
모든 노드가 이 규칙을 만족하면 해당 트리를 홀짝 트리 혹은 역 홀짝 트리라고 부른다.
트리의 개수와 각 트리가 홀짝 트리와 역 홀짝 트리의 개수를 반환한다.
개선 사항:
1. 문자열 비교 제거
StringBuilder
대신 정수 개수만으로 판단하여 비교 속도를 개선.두 가지 탐색 함수로 분리
checkHolZzak()
: 홀짝 트리인지 확인 checkReverseHolZzak()
: 역 홀짝 트리인지 확인 방문 배열(visited
)을 재사용
visited
배열을 각각 초기화하여 사용.재귀적 DFS 사용
노드와 간선 정보 저장
Map<Integer, List<Integer>>
을 사용하여 각 노드에 연결된 자식 노드를 저장.DFS로 홀짝성 검사
중복 검사 방지
visited
배열을 사용하여 중복 검사를 방지.결과 반환
answer[0]
: 홀짝 트리의 개수 answer[1]
: 역 홀짝 트리의 개수import java.util.*;
class Solution {
Map<Integer, List<Integer>> trees = new HashMap<>();
boolean[] visited = new boolean[1000001];
public int[] solution(int[] nodes, int[][] edges) {
int[] answer = new int[2];
// ✅ 1. 노드와 간선 정보 저장
for (int node : nodes) {
trees.put(node, new ArrayList<>());
}
for (int[] edge : edges) {
trees.get(edge[0]).add(edge[1]);
trees.get(edge[1]).add(edge[0]);
}
// ✅ 2. 홀짝 트리 검사
for (int node : nodes) {
if (!visited[node] && checkHolZzak(node, -1)) {
answer[0]++; // ✅ 홀짝 트리 개수 증가
}
}
// ✅ 3. 방문 배열 초기화
visited = new boolean[1000001];
// ✅ 4. 역 홀짝 트리 검사
for (int node : nodes) {
if (!visited[node] && checkReverseHolZzak(node, -1)) {
answer[1]++; // ✅ 역 홀짝 트리 개수 증가
}
}
return answer;
}
// ✅ **홀짝 트리** 검사 (노드의 값과 자식 개수의 홀짝성이 같아야 함)
private boolean checkHolZzak(int current, int parent) {
List<Integer> children = trees.get(current);
int childrenSize = children.size() - 1; // 부모 노드를 제외한 자식 수
if (parent == -1) {
childrenSize++; // 루트 노드는 부모가 없으므로 전체 개수 사용
}
// ✅ 노드의 값과 자식 수의 홀짝성이 같아야 함
if (current % 2 == childrenSize % 2) {
visited[current] = true; // 방문 표시
for (int child : children) {
if (child == parent) continue; // 부모 노드는 제외
if (!checkHolZzak(child, current)) {
visited[current] = false;
return false; // 하나라도 불일치하면 실패
}
}
} else {
return false; // 노드의 값과 자식 수의 홀짝성이 다르면 실패
}
return true; // 모든 조건을 만족하면 true 반환
}
// ✅ **역 홀짝 트리** 검사 (노드의 값과 자식 개수의 홀짝성이 달라야 함)
private boolean checkReverseHolZzak(int current, int parent) {
List<Integer> children = trees.get(current);
int childrenSize = children.size() - 1;
if (parent == -1) {
childrenSize++;
}
// ✅ 노드의 값과 자식 수의 홀짝성이 달라야 함
if (current % 2 != childrenSize % 2) {
visited[current] = true;
for (int child : children) {
if (child == parent) continue;
if (!checkReverseHolZzak(child, current)) {
visited[current] = false;
return false;
}
}
} else {
return false;
}
return true;
}
}
DFS를 사용하여 모든 노드를 탐색
checkHolZzak()
와 checkReverseHolZzak()
는 각각 한 번씩만 호출되므로 효율적이다.방문 배열(visited
)을 사용하여 중복 탐색 방지
시간복잡도:
visited
배열을 사용하므로 중복 탐색이 발생하지 않음 공간복잡도:
Map
과 visited
배열을 사용하여 메모리 사용을 최소화 int[] nodes = {1, 2, 3, 4, 5};
int[][] edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}};
int[] result = solution(nodes, edges);
System.out.println(Arrays.toString(result)); // [1, 0]
int[] nodes = {1, 2, 3, 4, 5, 6};
int[][] edges = {{1, 2}, {1, 3}, {3, 4}, {3, 5}, {5, 6}};
int[] result = solution(nodes, edges);
System.out.println(Arrays.toString(result)); // [0, 1]
int[] nodes = {1, 2, 3, 4, 5, 6, 7};
int[][] edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {3, 7}};
int[] result = solution(nodes, edges);
System.out.println(Arrays.toString(result)); // [1, 1]
int[] nodes = {1};
int[][] edges = {};
int[] result = solution(nodes, edges);
System.out.println(Arrays.toString(result)); // [1, 0]
첫 번째 시도 (문자열 사용)
두 번째 시도 (성공 - 최적화)
visited
배열로 중복 검사 방지