q
)은 각각 5개의 숫자로 이루어진 배열이다.ans
)의 값은 해당 질문과 암호의 교집합 요소 개수이다.answer
값을 증가시킨다.makeArr
)compareAns
)ans
배열의 값과 일치하면 다음 질문으로 넘어간다.answer++
을 증가시킨다.HashSet
으로 저장하여 교집합 검사 시 O(1)로 처리한다.import java.util.*;
class Solution {
int[] arr = new int[5]; // 현재 선택된 5개의 숫자
boolean[] visited; // 숫자 사용 여부 확인
int answer; // 최종 정답 개수
Set<Integer>[] set; // 각 질문의 숫자를 저장한 HashSet 배열
public int solution(int n, int[][] q, int[] ans) {
set = new Set[q.length];
// 각 질문의 숫자를 HashSet에 저장 (검색 속도 O(1))
for (int i = 0; i < q.length; i++) {
set[i] = new HashSet<>();
for (int j = 0; j < 5; j++) {
set[i].add(q[i][j]);
}
}
visited = new boolean[n + 1];
makeArr(0, 1, n, q, ans); // 조합 생성 및 검증 시작
return answer;
}
// ✅ 조합 생성 메서드 (Backtracking)
private void makeArr(int cnt, int cur, int n, int[][] q, int[] ans) {
// 5개를 모두 선택한 경우
if (cnt == 5) {
if (compareAns(q, ans)) answer++; // 조건에 맞으면 정답 증가
return;
}
// cur부터 시작하여 중복 없이 숫자 선택
for (int i = cur; i <= n; i++) {
if (visited[i]) continue; // 이미 사용한 숫자는 건너뜀
arr[cnt] = i; // 현재 숫자 선택
visited[i] = true;
makeArr(cnt + 1, i + 1, n, q, ans); // 재귀 호출로 다음 숫자 선택
visited[i] = false; // 백트래킹 (선택 해제)
}
}
// ✅ 질문과 현재 조합 비교 메서드
private boolean compareAns(int[][] q, int[] ans) {
for (int i = 0; i < q.length; i++) {
int sum = 0;
// 현재 조합(arr) 중 질문(set[i])에 포함된 숫자 개수 계산
for (int num : arr) {
if (set[i].contains(num)) sum++;
}
// 교집합 개수가 주어진 정답과 일치하지 않으면 실패
if (ans[i] != sum) return false;
}
return true; // 모든 질문의 조건을 만족하면 true 반환
}
}
makeArr()
메서드에서 모든 조합을 생성하며, compareAns()
로 질문과 비교한다.HashSet
에 저장하여 O(1)로 교집합 검사를 수행한다.O(q)
O(\binom{n}{5} \times q)
int n = 5;
int[][] q = {{1, 2, 3, 4, 5}};
int[] ans = {5};
결과: 1
int n = 5;
int[][] q = {
{1, 2, 3, 4, 5},
{1, 2, 3, 4, 6}
};
int[] ans = {5, 4};
결과: 1
n = 50
, 질문 개수 = 10O(\binom{n}{5} * q)
로, Set 덕분에 효율적으로 작동