프로그래머스 - 후보키 (Lv.2)
1 minute read
문제 링크
문제 설명
- 관계 데이터베이스에서 릴레이션의 튜플을 유일하게 식별할 수 있는 속성 또는 속성의 집합 중 다음 두 성질을 만족하는 것으 후보키라고 한다.
- 유일성: 릴레이션에 있는 모든 튜플에 대해 유일하게 식별되어야 한다.
- 최소성: 유일성을 가진 키를 구성하는 속성 중 하나라도 제외하는 경우 유일성이 깨지는 것을 의미한다. 즉, 릴레이션의 모든 튜플을 유일하게 식별하는 데 꼭 필요한 속성들로만 구성되어야 한다.
- 릴레이션이 주어질 때, 후보 키의 최대 개수를 구하라.
문제 접근
- 묶을 수 있는 속성들의 조합을 구한다.
- 위에서 찾은 속성들의 집합 혹은 속성이 유일성을 만족하는지 확인한다.
- 조합에 포함된 속성들이 각 행의 데이터 단위가 되어, 동일한 행이 존재하는지 확인한다.
- 위에서 찾은 속성들의 잡합 혹은 속성이 최소성을 만족하는지 확인한다.
- 속성들은 개수가 적은 것부터 후보키에 대한 조사를 하고, 후보키인 경우
history
배열에 넣어두어 관리해야 한다.
- 따라서,
history
에 담기는 속성들의 조합은 항상 유일성과 최소성을 만족한다.
- 최소성을 만족하는지 조사할 때, 조사 대상이 되는 문자열에서
history
의 원소들이 존재하는지를 파악하는데 substring 을 찾는 방법으로 구현했었다. 하지만, 이 경우에는 후보키가 [0,3] 이고 조사하는 집합은 [0,2,3] 일 때 최소성을 올바르게 평가하지 못하고 넘어가는 문제가 발생했다. 즉, 연속되지 않은 조합이라면 찾을 수 없는 것이었다.
- 위 로직은 반복문을 통해 직접 원소 하나하나를 비교하면서 문제를 해결할 수 있었다.
구현(All Pass)
#include <string>
#include <vector>
#include <memory.h>
#include <iostream>
#include <algorithm>
using namespace std;
int answer=0, colNum=0;
vector<string> history;
bool visited[8];
vector<int> cand;
bool checkUnique(vector<vector<string>>& relation){
vector<vector<string>> table;
for(int r=0; r<relation.size(); r++){
vector<string> list;
for(int i=0; i<cand.size(); i++){
list.push_back(relation[r][cand[i]]);
}
table.push_back(list);
int tuple = 0;
for(int i=0; i<table.size(); i++){
int cnt=0;
for(int j=0; j<table[i].size(); j++){
if(list[j]==table[i][j]) cnt++;
}
if(cnt == list.size()) tuple++;
}
if(tuple>1) return false;
}
return true;
}
bool checkMinimality(string combi){
for(int i=0; i<history.size(); i++){
int cnt = 0;
for(int j=0; j<history[i].length(); j++){
for(int k=0; k<combi.length(); k++){
if(history[i][j] == combi[k]) cnt++;
}
}
if(cnt == history[i].length()) return false;
}
return true;
}
void makeCombination(vector<vector<string>>& relation, int v, int n){
if(cand.size()==n){
string str;
for(int i=0; i<cand.size(); i++){
str.push_back(cand[i] + '0');
}
if(checkUnique(relation) && checkMinimality(str)){
answer++;
history.push_back(str);
}
return;
}
for(int i=v; i<colNum; i++){
if(visited[i]) continue;
visited[i] = true;
cand.push_back(i);
makeCombination(relation, i+1, n);
visited[i] = false;
cand.pop_back();
}
}
int solution(vector<vector<string>> relation) {
colNum = relation[0].size();
for(int i=1; i<=colNum; i++){
memset(visited, false, sizeof(visited));
makeCombination(relation, 0, i);
}
return answer;
}
Leave a comment