본문 바로가기

알고리즘/프로그래머스

[프로그래머스][2022 KAKAO BLIND RECRUITMENT][Python] 신고 결과 받기

문제를 정리해보자.

 

게시판 불량 이용자[용의자]를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발했다.

규칙은 다음과 같다.

 

1. 각 유저는 한 번에 한 명의 유저만 신고할 수 있다.

1-1) 신고 횟수에 제한이 없다.

1-2) 서로 다른 유저를 계속해서 신고할 수 있다.

1-3) 한 유저를 여러 번 신고할 수 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리된다.

 

2. k번 이상 신고된 유저는 게시판 이용이 정지된다.

2-1) 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 보낸다.

2-2) 유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송한다.

 

3. 자기 자신을 신고하는 경우는 없다.

 

위 규칙을 바탕으로, 유저별로 처리 결과 메일을 받은 횟수를 구하면 된다.

 


 

풀이를 생각해보자.

 

프로그래머스 예제 1번으로 생각해보자.

 

 

유저 목록, 신고내역, 정지당하는 신고횟수

 

 

신고내역

 

 

아래와 같이, 2차원 배열로 신고자와 용의자의 관계를 나타냈다.

 

 

[[0, 0, 1, 0], [1, 0, 1, 0], [0, 0, 0, 0], [1, 1, 0, 0]]

 

 

행은 용의자이고, 열은 신고자이다.

행렬의 값이 1이라면, 그 행의 사용자가 그 열의 사용자를 신고했다는 뜻이다.

 

각 행의 합은 그 행의 사용자가 신고당한 총 횟수이다.

예를 들어, 첫 번째 행의 사용자는 프로도이다. 신고당한 횟수는 총 2이다.

 

행렬표의 값이 1인 부분을 찾고, 그 행의 합이 k이상이면, 그 열의 사용자는 처리 결과 메시지를 받는다.

예를 들어, [3][1]을 보자. 프로도는 네오를 신고했다. 네오의 열의 합은 2이다.

따라서 프로도는 네오가 정지되었다는 메시지를 받는다.

 


 

구현해보자.

 

 

def solution(id_list, report, k):
    l = len(id_list)

    # 각 이름에 index 부여
    id_idx = {}
    for idx, value in enumerate(id_list):
        id_idx[value] = idx

    check = [[0] * l for _ in range(l)]
    spot = [[] for _ in range(l)]

    for value in report:
        A, B = value.split()  # 신고자, 용의자

        if check[id_idx[B]][id_idx[A]] == 0:  # 중복 신고 방지
            spot[id_idx[B]].append(id_idx[A])  # B를 신고한 사람 모음
        check[id_idx[B]][id_idx[A]] = 1  # A to B 신고 처리

    #  각 유저가 받은 결과 메일 수
    answer = [0] * l

    for i in range(l):  # i는 용의자, j는 신고자
        if k <= sum(check[i]):  # 각 행의 합, 신고 당한 총 횟수가 k이상?
            for j in spot[i]:  # 용의자를 신고한 사람 모음
                answer[j] += 1  # 신고자가 받아야 할 결과 += 1

    return answer


print(solution(["muzi", "frodo", "apeach", "neo"], ["muzi frodo","apeach frodo","frodo neo","muzi neo","apeach muzi"], 2))

 


 

시행착오

 

처음에 조건 1-3를 간과하고 문제를 풀었다. 그래서 다음과 같은 문제가 발생했다.

B가 정지된 유저가 되었을 때, A가 B를 4번 신고하면, A는 4번의 결과 메시지를 받는다. 

그래서 제출 코드에는 '중복 신고 방지'를 추가했다.

 

틀린 코드는 아래와 같다.

 

def solution(id_list, report, k):
    l = len(id_list)

    id_idx = {}
    for idx, value in enumerate(id_list):
        id_idx[value] = idx

    check = [[0] * l for _ in range(l)]
    spot = [[] for _ in range(l)]

    for value in report:
        A, B = value.split()  # 신고자, 용의자

        check[id_idx[B]][id_idx[A]] = 1
        spot[id_idx[B]].append(id_idx[A])

    print(check)

    #  각 유저가 받은 결과 메일 수
    answer = [0] * l
    for i in range(l):
        if k <= sum(check[i]):
            for j in spot[i]:
                answer[j] += 1

    return answer

print(solution(["con", "ryan"],["ryan con", "ryan con", "ryan con", "ryan con"], 1))

 


 

다른 사람의 풀이

출처

 

 

def solution(id_list, report, k):
    answer = [0] * len(id_list)    
    reports = {x : 0 for x in id_list}

    for r in set(report):
        reports[r.split()[1]] += 1

    for r in set(report):
        if reports[r.split()[1]] >= k:
            answer[id_list.index(r.split()[0])] += 1

    return answer

 

 

set을 이용해서 중복 신고를 미리 방지했다.

 


 

느낀 점

 

처음으로 카카오 기출문제를 풀어봤다. 지금까지 문제와 다르게 문제가 길고 조건이 까다롭다.

꼼꼼히 읽고 구현해야 모든 테스트 케이스를 통과할 것 같다.