파이썬 알고리즘 : 뉴스 클러스터링

자카드 유사도

2024년 1월 30일 알고리즘 문제풀이

문제

난이도

Lv.2

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def solution(str1, str2):
    def check(x):
        if x[0].islower() and x[1].islower():
            return True
        else:
            return False

    str1 = list(str1)
    str2 = list(str2)
    arr1 = []
    arr2 = []
    for i in range(len(str1) - 1):
        if str1[i].isupper():
            str1[i] = str1[i].lower()
        if str1[i + 1].isupper():
            str1[i + 1] = str1[i + 1].lower()
        if check(str1[i] + str1[i + 1]):
            arr1.append(str1[i] + str1[i + 1])
    for i in range(len(str2) - 1):
        if str2[i].isupper():
            str2[i] = str2[i].lower()
        if str2[i + 1].isupper():
            str2[i + 1] = str2[i + 1].lower()
        if check(str2[i] + str2[i + 1]):
            arr2.append(str2[i] + str2[i + 1])
    arr_all = arr1 + arr2
    arr_set = set(arr_all)
    n_max = 0
    n_min = 0

    for i in arr_set:
        n_max += max(arr1.count(i), arr2.count(i))
        if i in arr1 and i in arr2:
            n_min += min(arr1.count(i), arr2.count(i))

    if str1 == str2:
        answer = 65536
    elif not n_max and not n_min:
        answer = -1
    else:
        answer = int((n_min / n_max) * 65536)
    return answer

우선 문자열을 배열로 만들었다. 이후 각 원소가 대문자라면 소문자로 만들어주었다. 대문자, 소문자 구별이 없기 때문에 비교를 수월하게 하기 위함이다. 리스트의 두 원소를 붙여서 check 함수를 통해 둘다 소문자로 이루어진 알파벳인지 확인한다. 앞서서 대문자를 모두 소문자로 바꿔서 대문자일 가능성은 없다. 굳이 두개를 나눠야 하는 이유는, “%a” 에게 islower() 메서드를 사용하면 a가 소문자라 True를 반환하기 떄문이다. 앞에 %는 무관하다. 물론 “%” 처럼 알파벳이 없다면 False를 반환하다. 따라서 둘 다 알파벳으로 이루어졌는지 확인하기 위해 check() 함수에서는 둘을 나눴다. 이후 합집합의 갯수와 교집합의 갯수를 확인하기 위해 알파벳 2개가 원소인 리스트를 합쳐 set로 만들었다. 중복된 원소를 제거하여 교집합과 합집합 계산에 경우의 수를 낮추기 위해서다. 둘 다 공집합이면 -1을 반환해야하는데, 합집합 교집합이 0일 떄로 확인했다. 다만 예시 3번처럼, “%a!” 와 “%A!” 는 실제로 2개씩 잘랐을 때 모두 알파벳 2개로 이루어지지 않아(%a, a!) 집합이 없게 표시되지만 자카드 유사도는 1이다. 알파벳의 대문자 소문자 여부를 따지지 않기 때문에 완전히 동일한 두 문자열이기 떄문이다. 이럴 때를 확인하기위해 소문자로 바꾸고 리스트화 한 이후 둘이 같다면 자카드 유사도가 1이라 66536을 곱하여 나눈 정수부분을 그대로 출력하도록 했다.