[Programmers] 위장 (Python3)
문제
스파이들은 매일 다른 옷을 조합하여 입어 자신을 위장합니다.
예를 들어 스파이가 가진 옷이 아래와 같고 오늘 스파이가 동그란 안경, 긴 코트, 파란색 티셔츠를 입었다면 다음날은 청바지를 추가로 입거나 동그란 안경 대신 검정 선글라스를 착용하거나 해야 합니다.
종류 | 이름 |
---|---|
얼굴 | 동그란 안경, 검정 선글라스 |
상의 | 파란색 티셔츠 |
하의 | 청바지 |
겉옷 | 긴 코트 |
스파이가 가진 의상들이 담긴 2차원 배열 clothes가 주어질 때 서로 다른 옷의 조합의 수를 return 하도록 solution 함수를 작성해주세요.
제한사항
- clothes의 각 행은 [의상의 이름, 의상의 종류]로 이루어져 있습니다.
- 스파이가 가진 의상의 수는 1개 이상 30개 이하입니다.
- 같은 이름을 가진 의상은 존재하지 않습니다.
- clothes의 모든 원소는 문자열로 이루어져 있습니다.
- 모든 문자열의 길이는 1 이상 20 이하인 자연수이고 알파벳 소문자 또는 ‘_’ 로만 이루어져 있습니다.
- 스파이는 하루에 최소 한 개의 의상은 입습니다.
입출력 예
|clothes| return|
|:—:|:—:|
|[[“yellowhat”, “headgear”], [“bluesunglasses”, “eyewear”], [“green_turban”, “headgear”]] |5|
|[[“crowmask”, “face”], [“bluesunglasses”, “face”], [“smoky_makeup”, “face”]]| 3|
입출력 예 설명
예제 #1
headgear에 해당하는 의상이 yellow_hat, green_turban이고 eyewear에 해당하는 의상이 blue_sunglasses이므로 아래와 같이 5개의 조합이 가능합니다.
- yellow_hat
- blue_sunglasses
- green_turban
- yellow_hat + blue_sunglasses
- green_turban + blue_sunglasses
예제 #2
face에 해당하는 의상이 crow_mask, blue_sunglasses, smoky_makeup이므로 아래와 같이 3개의 조합이 가능합니다.
- crow_mask
- blue_sunglasses
- smoky_makeup
문제 풀이
처음에는 딕셔너리에 리스트로 종류에 따른 옷을 넣어서 그걸 또 조합으로 빼서 모든 경우의 수를 하나씩 더해가며 답을 구했는데, 모두 통과되는듯 싶더니 테스트 케이스 1번에서 계속 시간초과가 떴다. 다시 문제를 놓고 간단한 조합문제로 생각해보니까, 각각의 옷종류에 안입은 경우를 하나씩 추가해서 위의 예제 1로 예를 들면 headgear = [안입음, yellow_hat, grren_turban], eyewear = [안입음, blue_sunglasses] 으로 두면 두 종류이니까 3*2 = 6으로 모든 경우의 수를 구할 수 가 있었다. 여기서 아무것도 안입은 경우의 수 1을 빼주면 답이된다.
코드
1
2
3
4
5
6
7
8
9
10
11
12
def solution(clothes):
dic = {}
answer = 1
for cloth in clothes:
if cloth[1] in dic:
dic[cloth[1]]+=1
else:
dic[cloth[1]]= 1
for i in dic.values():
answer *= (i+1)
return answer-1
1
solution([["yellowhat", "headgear"], ["bluesunglasses", "eyewear"], ["green_turban", "headgear"]] )
1
5
노트
라이브러리를 이용해 예쁘게 푼 코드가 있어서 첨부한다.
reduce라는 처음 써보는 메서드도 있었다.
1
2
3
4
5
6
def solution(clothes):
from collections import Counter
from functools import reduce
cnt = Counter([kind for name, kind in clothes])
answer = reduce(lambda x, y: x*(y+1), cnt.values(), 1) - 1
return answer
개수를 세려면 무조건 Counter를 써주는게 편하다. Counter를 잘쓰자
reduce 함수는 functools 라이브러리를 통해서 import한다.
1
from functools import reduce
reduce() 함수는 여러개의 데이터를 대상으로 주로 누적 집계를 내기 위해서 사용한다.
reduce(집계 함수, 순회 가능한 데이터 [, 초기값])
예를들어 유저 5명의 데이터를 임의로 생성해보자.
1
2
3
4
5
users = [{'mail': 'gregorythomas@gmail.com', 'name': 'Brett Holland', 'sex': 'M', 'age': 73},
{'mail': 'hintoncynthia@hotmail.com', 'name': 'Madison Martinez', 'sex': 'F', 'age': 29},
{'mail': 'wwagner@gmail.com', 'name': 'Michael Jenkins', 'sex': 'M', 'age': 51},
{'mail': 'daniel79@gmail.com', 'name': 'Karen Rodriguez', 'sex': 'F', 'age': 32},
{'mail': 'ujackson@gmail.com', 'name': 'Amber Rhodes', 'sex': 'F', 'age': 42}]
이 데이터에서 reduce 함수를 사용해 유저들의 나이 합을 구해보자.
1
reduce(lambda acc, cur : acc+cur["age"], users,0)
1
227
reduce의 첫번째 파라미터는 함수가 들어가게 된다. 람다식이 들어올수도 있고, 정의 해놓은 함수일 수도 있다. 두번째 파라미터는 집계할 리스트, 세번재는 초기값을 받는다.
이번에는 유저 이메일만을 모아 목록으로 만들어보자.
1
reduce(lambda acc, cur: acc +[cur["mail"]],users,[])
1
2
3
4
5
['gregorythomas@gmail.com',
'hintoncynthia@hotmail.com',
'wwagner@gmail.com',
'daniel79@gmail.com',
'ujackson@gmail.com']
마찬가지로 첫번째 파라미터에 함수를 받고, acc의 초깃값을 []로 해준뒤, [cur[“mail”]]을 순차적으로 더해준다.
이렇게 reduce를 사용하면 간편하게 딕셔너리나 리스트의 값을 집계할 수 있다. 정말 유용한 라이브러리인 것 같으니 꼭 생각해주자.
딕셔너리하면 Counter, reduce 생각하기
댓글남기기