호기심 많은 분석가

[프로그래머스] 2018 KAKAO BLIND RECRUITMENT - [1차] 뉴스 클러스터링 본문

Coding/Coding Test & Algorithm

[프로그래머스] 2018 KAKAO BLIND RECRUITMENT - [1차] 뉴스 클러스터링

DA Hun 2021. 6. 30. 22:36
 

코딩테스트 연습 - [1차] 뉴스 클러스터링

뉴스 클러스터링 여러 언론사에서 쏟아지는 뉴스, 특히 속보성 뉴스를 보면 비슷비슷한 제목의 기사가 많아 정작 필요한 기사를 찾기가 어렵다. Daum 뉴스의 개발 업무를 맡게 된 신입사원 튜브

programmers.co.kr

내 풀이

import re
def solution(str1, str2):
    str1 = [str1[i:i+2] for i in range(len(str1)-1)]
    str1 = [re.sub('[^a-z]', '', i.lower()) for i in str1]
    str1 = [i for i in str1 if len(i)==2]
    str2 = [str2[i:i+2].lower() for i in range(len(str2)-1)]
    str2 = [re.sub('[^a-z]', '', i) for i in str2]
    str2 = [i for i in str2 if len(i)==2]

    length_str = len(str1) + len(str2)
    if length_str==0 :
        return 65536*1
    else : 
        result = 0
        for s1 in str1 : 
            if s1 in str2 :
                result += 1
                str2.remove(s1)
        return int(65536*(result/(length_str-result)))

 꽤 괜찮은 풀이라고 생각했으나 다른 사람들의 풀이를 보니 아직 한참 부족함을 깨달을 수 있었다.

문제 조건에 맞춰, 2개씩 소문자로(lower), 특수문자가 들어간 쌍은 삭제해주었다.(re.sub) 원래는 set을 사용하고 싶었지만, 중복도 허용한다 하여 for문을 이용해서 직접 개수를 세어주었다. 이미 세어졌는데 다시 세어지는 경우를 없애기 위해 remove 사용. 합집합의 경우 A집합+B집합-AB교집합이므로 마지막 식을 세워주고 마무리하였다.

 이제 다른 여러 풀이를 조합하여 나올 수 있는 최고 좋은 풀이를 찾아보자

다른 풀이 1

def solution(str1, str2):
    str1 = [str1[i:i+2].lower() for i in range(0, len(str1)-1) if str1[n:n+2].isalpha()]
    str2 = [str2[i:i+2].lower() for i in range(0, len(str2)-1) if str2[n:n+2].isalpha()]

    gyo = set(str1) & set(str2)
    hap = set(str1) | set(str2)

    if len(hap) == 0 :
        return 65536

    gyo_sum = sum([min(str1.count(gg), str2.count(gg)) for gg in gyo])
    hap_sum = sum([max(str1.count(hh), str2.count(hh)) for hh in hap])

    return int((gyo_sum/hap_sum)*65536)

 정말 경이로운 풀이다. 우선 isalpha라는 함수를 통해 알파벳으로 이루어지지 않은 쌍들을 날려주고 set을 이용해 교집합과 합집합을 구해준다. 그러면 중복되는 경우를 찾지 못하는 것 아닌가? 걱정은 금물, count함수를 이용해서 중복된 개수를 세어준다. isalpha와 count 모두 사용해보지 못한 함수인데 사용법을 기억하고 있어야겠다.

다른 풀이 2

from collections import Counter
def solution(str1, str2):
    # make sets
    s1 = [str1[i:i+2].lower() for i in range(len(str1)-1) if str1[i:i+2].isalpha()]
    s2 = [str2[i:i+2].lower() for i in range(len(str2)-1) if str2[i:i+2].isalpha()]
    if not s1 and not s2:
        return 65536
    c1 = Counter(s1)
    c2 = Counter(s2)
    answer = int(float(sum((c1&c2).values()))/float(sum((c1|c2).values())) * 65536)
    return answer

Counter의 사용법은 정말 무궁무진하다. 내 첫 풀이의 방향성이 이쪽이었는데 이렇게 사용할 수 있다는 걸 알아서 흥미롭다. 순서대로 코드를 본다면 점점 좋아지는 것을 배울 수 있다.