본문 바로가기

3. 알고리즘/프로그래머스

[python/해시] 26. 위장(feat. functools.reduce 함수)

728x90

문제 설명

스파이들은 매일 다른 옷을 조합하여 입어 자신을 위장합니다.

예를 들어 스파이가 가진 옷이 아래와 같고 오늘 스파이가 동그란 안경, 긴 코트, 파란색 티셔츠를 입었다면 다음날은 청바지를 추가로 입거나 동그란 안경 대신 검정 선글라스를 착용하거나 해야 합니다.

종류

이름
얼굴 동그란 안경, 검정 선글라스
상의 파란색 티셔츠
하의 청바지
겉옷 긴 코트

스파이가 가진 의상들이 담긴 2차원 배열 clothes가 주어질 때 서로 다른 옷의 조합의 수를 return 하도록 solution 함수를 작성해주세요.

 

제한사항

- clothes의 각 행은 [의상의 이름, 의상의 종류]로 이루어져 있습니다.

- 스파이가 가진 의상의 수는 1개 이상 30개 이하입니다.

- 같은 이름을 가진 의상은 존재하지 않습니다.

- clothes의 모든 원소는 문자열로 이루어져 있습니다.

- 모든 문자열의 길이는 1 이상 20 이하인 자연수이고 알파벳 소문자 또는 '_' 로만 이루어져 있습니다.

- 스파이는 하루에 최소 한 개의 의상은 입습니다.

 

입출력 예

clothes return
[[yellow_hat, headgear], [blue_sunglasses, eyewear], [green_turban, headgear]] 5
[[crow_mask, face], [blue_sunglasses, face], [smoky_makeup, face]] 3

 

입출력 예 설명

예제 #1

headgear에 해당하는 의상이 yellow_hat, green_turban이고 eyewear에 해당하는 의상이 blue_sunglasses이므로 아래와 같이 5개의 조합이 가능합니다.

1. yellow_hat
2. blue_sunglasses
3. green_turban
4. yellow_hat + blue_sunglasses
5. green_turban + blue_sunglasses

 


나의 코드

def solution(clothes):
    dic = {}
    mul = 1
    
    for x in clothes:  #의상 종류별 개수를 딕셔너리 형태로 생성한다.
        if x[1] in dic.keys():
            dic[x[1]] += 1
        else:
            dic[x[1]] = 2  #1이 아닌 2부터 시작하는 이유는 의상을 아예 입지 않는 경우도 생각해줘야 하기 때문이다.
            
    for y in dic:  #딕셔너리에 모인 개수를 모두 곱해준다.
        mul *= dic[y]
    return mul-1

딕셔너리를 만들어서 의상의 종류별로 개수를 구해줬다.

그리고 확률에서 경우의 수 문제를 풀듯이, 각 의상 종류별 개수에 1을 더한 값을 모두 곱해줬다.

마지막에 아무 의상을 입지 않는 경우는 빼줘야 하기 때문에 1을 빼준 값을 결과값으로 반환해줬다.

 

다른 풀이

from collections import Counter
from functools import reduce

def solution(clothes):
    cnt = Counter([kind for name, kind in clothes])
    answer = reduce(lambda x, y: x*(y+1), cnt.values(), 1) -1
    return answer

다른 풀이와 비교했을때, 코드는 매우 달랐지만 기본적인 아이디어는 비슷했다.

차이점은 1) dictionary를 for문을 돌려서 만들어주지 않고 Counter함수를 사용했다는 것, 2)for문으로 모든 딕셔너리 값을 곱해준 것이 아니라 reduce함수를 사용해서 한 번에 계산했다는 것이다.

 

 

*functools 모듈의 reduce 함수

여러 개의 데이터를 대상으로 누적 집계를 내기 위해서 사용한다.

reduce(집계 함수, 순회 가능한 데이터[, 초기값])의 형태로 작성한다.

이런식으로 작성하면 (((1+2)+3)+4)+5가 계산되어 15를 반환하게 된다.

answer = reduce(lambda x, y: x*(y+1), cnt.values(), 1) -1

'다른 풀이'에서 위 코드와 달리 세번째 인자에 1을 추가해준 것은 초기값이 1이기 때문이다.

따라서 모든 딕셔너리의 values에 1을 더하고 그것들을 곱한 결과값을 받을 수 있다.

 

 

 

728x90