본문 바로가기
Algorithm

[Python] 프로그래머스 | 가장 많이 받은 선물

by dokkisan 2024. 1. 5.

2024 카카오 윈터 인턴십 문제가 프로그래머스에 업데이트되었다.
그 중 가장 난이도가 쉬운 문제를 풀어봤다.
 
문제 풀이 시간이 종료되었을 때 코드는 아래와 같다.

def solution(friends, gifts):
    answer = 0
    
    # 이번달 선물 기록 바탕으로 담달 누가 많이 받을지, 얼마나 받을지
    # 이번달 두 사람 사이 더 많이 준 사람이 담달에 선물 1
    # 두 사람 없거나 똑같으면 선물지수 높은사람이 받음
        # 선물지수 같으면 담달 선물 x
    # 선물지수: 보낸 선물 - 받은 선물
    
    # send_dic = dict.fromkeys(friends,0)
    # receive_dic = dict.fromkeys(friends,0)
    gift_level = dict.fromkeys(friends,0)
    result_dic = dict.fromkeys(friends,0)
    data = [[0] * len(friends) for _ in range(len(friends))]
    
    for row in gifts:
        sender, receiver = row.split(' ')
        data[friends.index(sender)][friends.index(receiver)] += 1
    
    for friend in friends:
        sent = sum(data[friends.index(friend)])
        received = sum(data[i][friends.index(friend)] for i in range(len(friends)))
        gift_level[friend] = sent - received
        
    # 두 사람 비교
    for row in gifts:
        sender, receiver = row.split(' ')
        sender_index = friends.index(sender)
        receiver_index = friends.index(receiver)
        
        if data[sender_index][receiver_index] == data[receiver_index][sender_index]:
            # 선물지수 비교
            if gift_level[sender] > gift_level[receiver]:
                result_dic[sender] += 1
            elif gift_level[sender] < gift_level[receiver]: 
                result_dic[receiver] += 1
                  
        else:
            if data[sender_index][receiver_index] > data[receiver_index][sender_index]:
                result_dic[sender] += 1
            else:
                result_dic[receiver] += 1
    
    print(data)
    print(gift_level)
    print(result_dic)
    print(max(result_dic.values()))
    answer = max(result_dic.values())
    return answer

음.. 복잡하다
 

선물 주고 받은 데이터 저장하기

send_dic과 receive_dic은 사용자가 친구에게 선물을 주고 받은 count 값을 저장하기 위해 선언했었다.
문제를 풀어나가다보니 입출력 예를 참고해 선물을 주고 받은 데이터를 2차원 배열에 저장하면 불필요한 자료구조를 제거할 수 있다는 생각이 들었다.

입출력 예#1

2차원 배열 data에는 String을 저장할 수 없기 때문에, 입력값 friends의 인덱스와 동일하게 2차원 배열 인덱싱을 했다.
입출력 예와 같이 data의 행은 선물을 준 사람, 열은 선물을 받은 사람이다.

for row in gifts:
        sender, receiver = row.split(' ')
        data[friends.index(sender)][friends.index(receiver)] += 1

 
 

기존 코드의 문제점과 해결 과정

1. 선물지수 계산 시 잘못된 인덱싱

data에서 하나의 행에 대한 열을 모두 더하면 그 행의 사용자가 보낸 선물의 총합를 얻을 수 있다.
그래서 받은 선물의 총합을 계산하기위해 하나의 열에 대한 행을 모두 더하면 된다고 생각했다.

receive = sum(data[::][friends.index(friend)])

 

2차원 배열 접근

인덱스 슬라이싱[::]을 이용해 상위 차원의 리스트(열, 받은 사람)에 접근하려고 했다.
그런데 인덱스 슬라이싱은 내가 생각한 것과 반대로 하나의 행에 대한 열을 모두 더하고 있었다.
자바의 2차원 배열을 생각했던 나는 인덱스 슬라이싱이 2차원 배열과 무관하다는 것을 알게 됐다.
 
인덱스 슬라이싱은 2차원 배열의 경우, 최상위 차원 리스트를 지정된 인덱스 만큼 추출해 새로운 리스트를 복사한다.
따라서 내 코드에서는 새로운 리스트를 생성하고, 받은 사람이 아닌 선물을 준 사람에 접근하고 있었다.
 
각 행마다 접근하기 위해서는 리스트 컴프리헨션을 이용하면 된다.

    for friend in friends:
        sent = sum(data[friends.index(friend)])
        received = sum(data[i][friends.index(friend)] for i in range(len(friends)))
        gift_level[friend] = sent - received

반복문을 이용한 리스트 컴프리헨션으로 수정했다.
 

2. 다음 달 선물 예측

for 문을 gifts에서 돌리고 있어 정확한 값이 나오지 않았다. 이 부분을 friends로 수정했다.
잘못된 반복문에 더불어 문제 설명의 흐름 그대로 조건문을 작성하다보니 코드가 복잡해지고, 정확한 answer가 계산되지 않는다.

    # 두 사람 비교
    for row in gifts:
        sender, receiver = row.split(' ')
        sender_index = friends.index(sender)
        receiver_index = friends.index(receiver)
        
        if data[sender_index][receiver_index] == data[receiver_index][sender_index]:
            # 선물지수 비교
            if gift_level[sender] > gift_level[receiver]:
                result_dic[sender] += 1
            elif gift_level[sender] < gift_level[receiver]: 
                result_dic[receiver] += 1
                  
        else:
            if data[sender_index][receiver_index] > data[receiver_index][sender_index]:
                result_dic[sender] += 1
            else:
                result_dic[receiver] += 1

 
아래는 수정된 코드이다.

    for friend in friends:
        for other in friends:
            if friend != other:
                sender_gifts = data[friends.index(friend)][friends.index(other)]
                receiver_gifts = data[friends.index(other)][friends.index(friend)]
                if sender_gifts > receiver_gifts or (
                        sender_gifts == receiver_gifts and gift_level[friend] > gift_level[other]):
                    result_dic[friend] += 1

풀면서 많이 애를 먹고 문법에 대한 아쉬움이 컸지만 그만큼 성취감을 느낄 수 있었다!