[ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€] 후보킀 / 파이썬 / (μ§‘ν•©, λΉ„νŠΈλ§ˆμŠ€ν¬)
Problem Solving πŸ”₯/ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€

[ν”„λ‘œκ·Έλž˜λ¨ΈμŠ€] 후보킀 / 파이썬 / (μ§‘ν•©, λΉ„νŠΈλ§ˆμŠ€ν¬)

λ¬Έμ œμ„€λͺ…

후보킀

ν”„λ Œμ¦ˆλŒ€ν•™κ΅ 컴퓨터곡학과 쑰ꡐ인 μ œμ΄μ§€λŠ” λ„€μ˜€ ν•™κ³Όμž₯λ‹˜μ˜ μ§€μ‹œλ‘œ, ν•™μƒλ“€μ˜ 인적사항을 μ •λ¦¬ν•˜λŠ” 업무λ₯Ό λ‹΄λ‹Ήν•˜κ²Œ λ˜μ—ˆλ‹€.

그의 ν•™λΆ€ μ‹œμ ˆ ν”„λ‘œκ·Έλž˜λ° κ²½ν—˜μ„ λ˜μ‚΄λ €, λͺ¨λ“  인적사항을 λ°μ΄ν„°λ² μ΄μŠ€μ— λ„£κΈ°λ‘œ ν•˜μ˜€κ³ , 이λ₯Ό μœ„ν•΄ 정리λ₯Ό ν•˜λ˜ 쀑에 후보킀(Candidate Key)에 λŒ€ν•œ 고민이 ν•„μš”ν•˜κ²Œ λ˜μ—ˆλ‹€.

후보킀에 λŒ€ν•œ λ‚΄μš©μ΄ 잘 κΈ°μ–΅λ‚˜μ§€ μ•Šλ˜ μ œμ΄μ§€λŠ”, μ •ν™•ν•œ λ‚΄μš©μ„ νŒŒμ•…ν•˜κΈ° μœ„ν•΄ λ°μ΄ν„°λ² μ΄μŠ€ κ΄€λ ¨ μ„œμ μ„ ν™•μΈν•˜μ—¬ μ•„λž˜μ™€ 같은 λ‚΄μš©μ„ ν™•μΈν•˜μ˜€λ‹€.

  • 관계 λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ λ¦΄λ ˆμ΄μ…˜(Relation)의 νŠœν”Œ(Tuple)을 μœ μΌν•˜κ²Œ 식별할 수 μžˆλŠ” 속성(Attribute) λ˜λŠ” μ†μ„±μ˜ μ§‘ν•© 쀑, λ‹€μŒ 두 μ„±μ§ˆμ„ λ§Œμ‘±ν•˜λŠ” 것을 후보 ν‚€(Candidate Key)라고 ν•œλ‹€.
    • μœ μΌμ„±(uniqueness) : λ¦΄λ ˆμ΄μ…˜μ— μžˆλŠ” λͺ¨λ“  νŠœν”Œμ— λŒ€ν•΄ μœ μΌν•˜κ²Œ μ‹λ³„λ˜μ–΄μ•Ό ν•œλ‹€.
    • μ΅œμ†Œμ„±(minimality) : μœ μΌμ„±μ„ κ°€μ§„ ν‚€λ₯Ό κ΅¬μ„±ν•˜λŠ” 속성(Attribute) 쀑 ν•˜λ‚˜λΌλ„ μ œμ™Έν•˜λŠ” 경우 μœ μΌμ„±μ΄ κΉ¨μ§€λŠ” 것을 μ˜λ―Έν•œλ‹€. 즉, λ¦΄λ ˆμ΄μ…˜μ˜ λͺ¨λ“  νŠœν”Œμ„ μœ μΌν•˜κ²Œ μ‹λ³„ν•˜λŠ” 데 κΌ­ ν•„μš”ν•œ μ†μ„±λ“€λ‘œλ§Œ κ΅¬μ„±λ˜μ–΄μ•Ό ν•œλ‹€.

μ œμ΄μ§€λ₯Ό μœ„ν•΄, μ•„λž˜μ™€ 같은 ν•™μƒλ“€μ˜ 인적사항이 μ£Όμ–΄μ‘Œμ„ λ•Œ, 후보 ν‚€μ˜ μ΅œλŒ€ 개수λ₯Ό κ΅¬ν•˜λΌ.

μœ„μ˜ 예λ₯Ό μ„€λͺ…ν•˜λ©΄, ν•™μƒμ˜ 인적사항 λ¦΄λ ˆμ΄μ…˜μ—μ„œ λͺ¨λ“  학생은 각자 μœ μΌν•œν•™λ²ˆμ„ κ°€μ§€κ³  μžˆλ‹€. λ”°λΌμ„œν•™λ²ˆμ€ λ¦΄λ ˆμ΄μ…˜μ˜ 후보 ν‚€κ°€ 될 수 μžˆλ‹€.
κ·Έλ‹€μŒμ΄λ¦„μ— λŒ€ν•΄μ„œλŠ” 같은 이름(apeach)을 μ‚¬μš©ν•˜λŠ” 학생이 있기 λ•Œλ¬Έμ—,이름은 후보 ν‚€κ°€ 될 수 μ—†λ‹€. κ·ΈλŸ¬λ‚˜, λ§Œμ•½ [이름,전곡]을 ν•¨κ»˜ μ‚¬μš©ν•œλ‹€λ©΄ λ¦΄λ ˆμ΄μ…˜μ˜ λͺ¨λ“  νŠœν”Œμ„ μœ μΌν•˜κ²Œ 식별 κ°€λŠ₯ν•˜λ―€λ‘œ 후보 ν‚€κ°€ 될 수 있게 λœλ‹€.
λ¬Όλ‘  [이름,전곡,ν•™λ…„]을 ν•¨κ»˜ μ‚¬μš©ν•΄λ„ λ¦΄λ ˆμ΄μ…˜μ˜ λͺ¨λ“  νŠœν”Œμ„ μœ μΌν•˜κ²Œ 식별할 수 μžˆμ§€λ§Œ, μ΅œμ†Œμ„±μ„ λ§Œμ‘±ν•˜μ§€ λͺ»ν•˜κΈ° λ•Œλ¬Έμ— 후보 ν‚€κ°€ 될 수 μ—†λ‹€.
λ”°λΌμ„œ, μœ„μ˜ 학생 μΈμ μ‚¬ν•­μ˜ ν›„λ³΄ν‚€λŠ”ν•™λ²ˆ, [이름,전곡] 두 κ°œκ°€ λœλ‹€.

λ¦΄λ ˆμ΄μ…˜μ„ λ‚˜νƒ€λ‚΄λŠ” λ¬Έμžμ—΄ λ°°μ—΄ relation이 λ§€κ°œλ³€μˆ˜λ‘œ μ£Όμ–΄μ§ˆ λ•Œ, 이 λ¦΄λ ˆμ΄μ…˜μ—μ„œ 후보 ν‚€μ˜ 개수λ₯Ό return ν•˜λ„λ‘ solution ν•¨μˆ˜λ₯Ό μ™„μ„±ν•˜λΌ.

μ œν•œμ‚¬ν•­

  • relation은 2차원 λ¬Έμžμ—΄ 배열이닀.
  • relation의 컬럼(column)의 κΈΈμ΄λŠ”1이상8μ΄ν•˜μ΄λ©°, 각각의 μ»¬λŸΌμ€ λ¦΄λ ˆμ΄μ…˜μ˜ 속성을 λ‚˜νƒ€λ‚Έλ‹€.
  • relation의 둜우(row)의 κΈΈμ΄λŠ”1이상20μ΄ν•˜μ΄λ©°, 각각의 λ‘œμš°λŠ” λ¦΄λ ˆμ΄μ…˜μ˜ νŠœν”Œμ„ λ‚˜νƒ€λ‚Έλ‹€.
  • relation의 λͺ¨λ“  λ¬Έμžμ—΄μ˜ κΈΈμ΄λŠ”1이상8μ΄ν•˜μ΄λ©°, μ•ŒνŒŒλ²³ μ†Œλ¬Έμžμ™€ 숫자둜만 이루어져 μžˆλ‹€.
  • relation의 λͺ¨λ“  νŠœν”Œμ€ μœ μΌν•˜κ²Œ 식별 κ°€λŠ₯ν•˜λ‹€.(즉, μ€‘λ³΅λ˜λŠ” νŠœν”Œμ€ μ—†λ‹€.)

μž…μΆœλ ₯ 예

relationresult

[["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

μž…μΆœλ ₯ 예 μ„€λͺ…

μž…μΆœλ ₯ 예 #1
λ¬Έμ œμ— μ£Όμ–΄μ§„ λ¦΄λ ˆμ΄μ…˜κ³Ό κ°™μœΌλ©°, 후보 ν‚€λŠ” 2κ°œμ΄λ‹€.

풀이

μš°μ„ , λ¬Έμ œκ°€ 어렡닀기보닀, κ΅¬ν˜„μ΄ λΉ‘μ„Ό λ¬Έμ œμ΄λ‹€.
κ²°κ΅­ 문제λ₯Ό ν’€μ§€ λͺ»ν–ˆκ³ , λ…Έκ°€λ‹€λ₯Ό λ°˜λ³΅ν•˜λ‹€κ°€ 해닡을 봐버렸닀.
카카였 μ½”ν…Œ 문제인데, 이 정도 κ΅¬ν˜„μ΄λ©΄ Python이 μ•„λ‹ˆλ©΄ ν’€κΈ° ꡉμž₯히 λΉ‘μ„Έλ‹€. μΉ΄μΉ΄μ˜€λŠ” 이런 μœ ν˜•μ˜ 문제λ₯Ό μ’‹μ•„ν•˜λŠ” 것 같은데, 개인적인 μƒκ°μœΌλ‘œ 카카였 μ½”ν…ŒλŠ” 파이썬이 ꡉμž₯히 μœ λ¦¬ν•˜λ‹€.(C++둜만 500λ¬Έμ œμ΄μƒμ„ ν’€μ—ˆλŠ”λ°, μ΅œκ·Όμ— Python 으둜 κ°ˆμ•„νƒ„ μ΄μœ λ‹€.)
이 λ¬Έμ œλŠ” Set 자료ꡬ쑰λ₯Ό κΉŠμˆ™νžˆ λ¬»λŠ” λ¬Έμ œμ˜€κ³ , ν˜Ήμ€ Bit maskλ‘œλ„ ν’€ 수 μžˆλ‹€. 개인적으둜 λ‚œμ΄λ„ 3은 μ€˜μ•Όν•  것 같은데, λ‚œμ΄λ„ 2둜 λ°°μ •λ˜μ–΄μžˆλŠ”κ²Œ μ‹ κΈ°ν•œ λ¬Έμ œμ˜€λ‹€.

ν•΄λ‹΅μ˜ 과정은, μš°μ„  λͺ¨λ“  μΌ€μ΄μŠ€λ₯Ό allCandidates 배열에 λ„£μ—ˆκ³ , 이 쀑 ν›„λ³΄ν‚€μ˜ 첫번째 μ„±μ§ˆμΈ μœ μΌμ„±μ„ λ§Œμ‘±ν•˜μ§€ μ•ŠλŠ” μΌ€μ΄μŠ€λ₯Ό λ°°μ œν•œλ‹€.

κ·Έ ν›„, μ΅œμ†Œμ„±μ„ λ§Œμ‘±ν•˜μ§€ μ•ŠλŠ” μΌ€μ΄μŠ€λ₯Ό ν•œλ²ˆ 더 λ°°μ œν•˜μ—¬ ν’€ 수 μžˆλ‹€.

from itertools import combinations

def solution(relation):
    n_row = len(relation)
    n_col = len(relation[0])
    allCandidates = []
    for i in range(1, n_col+1):
        allCandidates.extend(combinations(range(n_col), i))
    print(allCandidates)

    candidateKeys = []
    for candidate in allCandidates:
        tuples = [ tuple(row[idx] for idx in candidate  ) for row in relation ]
        if len(set(tuples)) == n_row:
            candidateKeys.append(candidate)

    answer = set(candidateKeys[:])
    print(answer)
    for i in range(len(candidateKeys)):
        for j in range(i+1, len(candidateKeys)):
            if len(candidateKeys[i]) == len(set(candidateKeys[i]).intersection(set(candidateKeys[j]))):
                answer.discard(candidateKeys[j])

    return len(answer)

무엇을 κ°œμ„ ν•  수 μžˆλŠ”κ°€?

사싀 이 λ¬Έμ œλŠ” 개인적으둜 Bit Mask λ¬Έμ œμ— 가깝닀고 μƒκ°ν•œλ‹€.
λ§Œμ•½ Python이 μ•„λ‹Œ, λ‹€λ₯Έ μ–Έμ–΄λ‘œ 이 문제λ₯Ό ν’€λ €λ©΄ 거의 무쑰건 Bit Mask을 써야할 것이닀.. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ μ½”λ“œ 라인이 100쀄이 λ„˜μ–΄κ°ˆμ§€ λͺ¨λ₯Έλ‹€..
λ‹€μŒ μ½”λ“œλŠ” Bit Mask 풀이이며, 개인적으둜 이 μ½”λ“œλ₯Ό 보고 μžκ΄΄κ°μ— λ“€μ—ˆλ‹€.
적은 수의 집합은 무쑰건 λΉ„νŠΈλ§ˆμŠ€ν¬λ‘œ ν’€ 수 μžˆλŠ”λ°, 이λ₯Ό μƒκ°ν•˜μ§€ λͺ»ν•˜λ‹€λ‹ˆ.. PSλ₯Ό λ„ˆλ¬΄ μ‰¬μ—ˆλ‚˜λ³΄λ‹€.

 def solution(relation):
    answer_list = list()
    for i in range(1, 1 << len(relation[0])):
        tmp_set = set()
        for j in range(len(relation)):
            tmp = ''
            for k in range(len(relation[0])):
                if i & (1 << k):
                    tmp += str(relation[j][k])
            tmp_set.add(tmp)

        if len(tmp_set) == len(relation):
            not_duplicate = True
            for num in answer_list:
                if (num & i) == num:
                    not_duplicate = False
                    break
            if not_duplicate:
                answer_list.append(i)
    return len(answer_list)