문제
- 문제 링크
- 문제 설명: 릴레이션에 모든 row 가 유니크하도록 하는 컬럼 조합의 개수 반환
- 어떤 컬럼 조합에 대해 데이터들 중 같은 데이터가 없으면 그 컬럼 조합은 후보키가 될 수 있다.
- 어떤 컬럼 조합을 포함하는 컬럼 조합은 후보키가 될 수 없다. -> 최소성
- 입력
- relation은 2차원 문자열 배열
- relation의 컬럼(column)의 길이는 1 이상 8 이하이며, 각각의 컬럼은 릴레이션의 속성을 나타냄
- relation의 로우(row)의 길이는 1 이상 20 이하이며, 각각의 로우는 릴레이션의 튜플을 나타냄
- relation의 모든 문자열의 길이는 1 이상 8 이하이며, 알파벳 소문자와 숫자로만 이루어져 있음
- relation의 모든 튜플은 유일하게 식별 가능 (즉, 중복되는 튜플은 없다.)
- 출력: 컬럼 조합의 개수
relation | result |
[["100","ryan","music","2"], ["200","apeach","math","2"], ["300","tube","computer","3"], ["400","con","computer","4"], ["500","muzi","music","3"], ["600","apeach","music","2"]] |
2 |
풀이
- relation을 이용해서 컬럼마다 데이터를 저장 -> 인덱스: 컬럼명, 값: 해당 컬럼의 데이터 목록
- 컬럼은 최대 8개 있으므로 DFS 를 이용해서 컬럼별 데이터를 조합해서 중복되는 데이터가 없으면 후보키 목록에 추가
- "1번 컬럼 -> 2번 컬럼" 순서로 조합하는 것과 "2번 컬럼 -> 1번 컬럼" 순서로 조합하면 결과가 같으므로 인자로 현재 조합할 시작 컬럼을 추가해서 중복을 방지
- 컬럼 개수가 8개이므로 정수형 변수에 비트로 조합한 컬럼 목록 저장 가능
- 최소성을 만족하는지 찾기 위해, 현재 중복 데이터가 없는 후보키가 이전에 후보키 목록들 중에 포함되는지 검사
- 후보키 목록들 중 현재 후보키를 포함하는 것들이 있으면 모두 제거
- 예를 들어, 0 1 2 … 순서로 조합을 만들다 보니 뒤에 5 7 만 있으면 후보키가 되는 경우 앞에 만들어진 후보키들을 없애야 함. 예를 들어 0 1 5 7 이 있고 0 2 3 5 7 이 있으면 둘 다 없애고 5 7만 저장
- 끝으로 후보키 목록의 크기를 반환
#include <string>
#include <vector>
#include <set>
using namespace std;
vector<string> relation_by_col[8]; // 컬럼별 데이터
int num_cols, num_rows;
set<int> candidates; // 후보키 목록
// c := 컬럼 인덱스
// cand := 조합된 컬럼 인덱스를 비트로 저장한 정수형 변수
// comb := 조합된 컬럼의 데이터들
void dfs(int c, int cand, vector<vector<string>>& comb) {
if (comb.size() > 0) { // 하나라도 조합된 컬럼이 있으면
set<string> s;
for (int i = 0; i < num_rows; i++) {
string data;
for (int j = 0; j < comb.size(); j++)
data += comb[j][i] + " ";
s.insert(data);
}
// 데이터가 중복이 없는지 검사
if (s.size() == num_rows) {
// 현재 후보키를 포함하는 후보키들은 모두 제거
while (1) {
bool minimality = true;
for (auto& c : candidates) {
if ((c & cand) == cand) {
candidates.erase(c);
minimality = false;
break;
}
}
// 최소성을 만족하면 break
if (minimality) break;
}
candidates.insert(cand); // 후보키에 추가
return;
}
}
for (int i = c; i < num_cols; i++) {
comb.push_back(relation_by_col[i]);
dfs(i+1, cand | (1 << i), comb); // 컬럼 조합 생성
comb.pop_back();
}
}
int solution(vector<vector<string>> relation) {
int answer = 0;
num_rows = relation.size();
num_cols = relation[0].size();
for (int i = 0; i < relation.size(); i++)
for (int j = 0; j < num_cols; j++)
relation_by_col[j].push_back(relation[i][j]);
vector<vector<string>> comb;
dfs(0, 0, comb);
answer = candidates.size();
return answer;
}
'Algorithm > Problem Solving' 카테고리의 다른 글
[SlidingWindow] (프로그래머스 Lv 3) 광고 삽입 (0) | 2021.04.24 |
---|---|
[구현] (프로그래머스 Lv 3) 자물쇠와 열쇠 (0) | 2021.04.24 |
[BinarySearch, DFS] (프로그래머스 Lv 2) 순위 검색 (0) | 2021.04.24 |
[DFS, Bit-Operation, Set] (프로그래머스 Lv 2) 메뉴 리뉴얼 (0) | 2021.04.24 |
[Brute-Force, String] (프로그래머스 Lv 2) 문자열 압축 (0) | 2021.04.24 |