Coding Test/프로그래머스

[프로그래머스] 위클리 챌린지 6주차 : 복서 정렬하기(python)

hzoooo 2021. 9. 16. 23:58

[문제 설명]

 

코딩테스트 연습 - 6주차_복서 정렬하기

복서 선수들의 몸무게 weights와, 복서 선수들의 전적을 나타내는 head2head가 매개변수로 주어집니다. 복서 선수들의 번호를 다음과 같은 순서로 정렬한 후 return 하도록 solution 함수를 완성해주세요

programmers.co.kr


[나의 답안]

def solution(weights, head2head):
    WEIGHT = 0
    WIN_COUNT = 1
    WIN_COUNT_OW = 2

    boxer_info_dict = {num: [weight] for num, weight in enumerate(weights)}

    for i, record in enumerate(head2head):
        record = list(record)
        win_count = record.count('W')
        lose_count = record.count('L')
        if win_count + lose_count != 0:
            boxer_info_dict[i].append(win_count/(win_count + lose_count))
        else:
            boxer_info_dict[i].append(0)

        search_idx = 0
        win_count_overweight = 0
        for _ in range(win_count):
            opponent_idx = search_idx + record[search_idx:].index('W')
            my_weight = boxer_info_dict[i][WEIGHT]
            your_weight = boxer_info_dict[opponent_idx][WEIGHT]
            if my_weight < your_weight:
                win_count_overweight += 1
            search_idx = opponent_idx + 1
        boxer_info_dict[i].append(win_count_overweight)

    answer = [num[0]+1 for num in sorted(boxer_info_dict.items(), key=lambda x:(x[1][WIN_COUNT], x[1][WIN_COUNT_OW], x[1][WEIGHT], -x[0]), reverse=True)]

    return answer

어쩌다 보니, 2시간 넘게 풀어버렸다.

승률로 비교를 해야되는데 승수만 비교하려고 꼼수를 쓰려다가, 왜 자꾸 틀리는 지 생각하기보다 짜증만 내다가 문제점을 찾았다.

WWNNL 과, WWNNN 인 사람의 승률을 비교해보면, 66%, 100% 이기 때문에 win_count로 비교하면 안된다는 것을 거의 2시간만에 깨우쳤다. 되게 한심하게 시간을 썼다..

2중 for loop이 너무 심플하고 쉬운 방법 같아서, 먼저 win_count를 구한 후 count 횟수 만큼 비교를 하려고 코드를 이렇게 짰는데,

생각해보니 win_count를 구하는 과정에서 for문이 돌아가기 때문에, 더 비효율 적인 것 같다.

아래 접은 글( 더보기 )에서, 다른 사람의 코드와 실행속도를 비교해 봤다.

더보기
내코드 : 왼쪽, 다른 사람코드 : 오른쪽

2중 for loop 돌린 사람과 테스트를 해봤더니, 평균적으로 내 코드 수행시간이 훨씬 느리게 나왔다.

근데 메모리는 내가 조금 적게 썼다. 개선해봐야지!

그래도 뿌듯한 건, sorted 안에 lambda 식을 직접 처음 써본 점이다.

- 내림차순 : 승률(1순위), 초과무게 승리 수(2순위), 무게(3순위)

- 오름차순 : 선수 번호(4순위) 를 위해

key=lambda x:(x[1][WIN_COUNT], x[1][WIN_COUNT_OW], x[1][WEIGHT], -x[0]), reverse=True 와 같이 코드를 구성했다.


 

※회고

1. 변수명 바꾸기 : 오랜 시간 동안 오류를 찾으려고 끙끙대다가, 승률을 WIN_COUNT라고 적어두었다 → 수정

   다른 몇몇 변수들도 바꿨다.

 

2. 2중 for loop로 변경

def solution(weights, head2head):
    WEIGHT = 0
    WIN_RATE = 1
    WIN_OVERWEIGHT_COUNT = 2

    boxer_info_dict = {num: [weight] for num, weight in enumerate(weights)}

    for i in range(len(head2head)):
        record = list(head2head[i])
        win_count = 0
        lose_count = 0
        win_overweight_count = 0
        for j in range(len(head2head)):
            if head2head[i][j] == 'W':
                win_count += 1
                my_weight = boxer_info_dict[i][WEIGHT]
                your_weight = boxer_info_dict[j][WEIGHT]
                if my_weight < your_weight:
                    win_overweight_count += 1

            elif head2head[i][j] == 'L':
                lose_count += 1
        try:
            boxer_info_dict[i].append((win_count / (win_count + lose_count)))
        except:
            boxer_info_dict[i].append(0)
        boxer_info_dict[i].append(win_overweight_count)

    answer = [num[0]+1 for num in sorted(boxer_info_dict.items(), key=lambda x:(x[1][WIN_RATE], x[1][WIN_OVERWEIGHT_COUNT], x[1][WEIGHT], -x[0]), reverse=True)]

    return answer

수정 하고 나서, 이전 코드와 수행시간 및 메모리를 비교해보니 아래와 같다.

평균 메모리 사용량도 조금 줄고, 수행속도가 많이 개선되었다.

왼쪽 : before, 오른쪽 : after