문제 설명
스파이들은 매일 다른 옷을 조합하여 입어 자신을 위장합니다.
예를 들어 스파이가 가진 옷이 아래와 같고 오늘 스파이가 동그란 안경,
긴 코트, 파란색 티셔츠를 입었다면 다음날은 청바지를 추가로 입거나
동그란 안경 대신 검정 선글라스를 착용하거나 해야 합니다.
종류 | 이름 |
얼굴 | 동그란 안경, 검정 선글라스 |
상의 | 파란색 티셔츠 |
하의 | 청바지 |
겉옷 | 긴 코트 |
스파이가 가진 의상들이 담긴 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
from collections import Counter
def solution(clothes):
counter = {}
lists = []
answer = 1
for i in range(len(clothes)):
lists.append(clothes[i][1])
counter = Counter(lists)
values = list(counter.values())
for i in range(len(values)):
answer *= (values[i] + 1)
answer -= 1
return answer
이전에 배운 collections 라이브러리의 Counter 클래스를 활용했다.
clothes 각 원소의 1번만 불러서 lists라는 새로운 리스트에 저장했다.
따로 복장 형태의 원소만 저장한 이유는 다음과 같다.
headgear 2개와 eyewear 1개가 있을 때 경우의 수는 다음과 같다.
1. headgear A
2. headgear B
3. eyewear
4. headgear A + eyewear
5. headgear B + eyewear
headgear는 한개씩 쓰거나(2가지), 안쓰거나(1가지)로 총 3가지 경우가 있다.
eyewear는 쓰거나(1가지), 안쓰거나(1가지)로 총 2가지 경우가 있다.
그런데 headgear와 eyewear를 모두 쓰지 않는 경우는 없으므로
총 경우의 수는 3 x 2 - 1 = 5가 된다.
따라서 굳이 복장의 세세한 이름까지 저장할 필요없이 복장의 형태가 무엇인지만 알아도 계산이 된다.
그리고 counter 사전 자료형에 Counter(lists)로 함수를 이용하여 list의 원소의 개수가 몇개인지를 계산했다.
counter 사전 자료형의 value를 따로 values라는 리스트에 저장했다.
그러면 values 리스트에는 counter의 value 값, 즉 headgear와 eyewear 등이 몇개가 있는지만 저장된다.
마지막으로 for 문을 이용해서 values의 값을 불러서
앞서 설명한 식대로 answer에 곱하고 마지막에 1을 빼면 된다.
answer에 값이 곱해지기 위해서 초기값으로 answer=1을 두었다.
대다수의 풀이
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
또 처음보는 모듈이 등장
functools 내장 모듈의 reduce() 함수는 여러 개의 데이터를 대상으로 누적 집계를 낼 때 사용한다.
reduce는 초기값에 대해서 집계 함수의 계산을 거친 뒤 그 결과를 return하여
다음 리스트의 원소를 꺼낼 때 재사용한다.
from functools import reduce
reduce(집계 함수, 리스트, 초기값)
우선 Counter([kind for name, kind in clothes])를 설명한다.
for name, kind in clothes
-> clothes 안에 있는 0번째 인덱스 원소는 name, 1번째 인덱스 원소는 kind로 지정
그리고 kind를 앞에 적어서 kind만 뽑아서 [] 리스트로 저장한다.
예를 들어 ['headgear', 'eyewear', 'headgear']처럼이다.
그리고 Counter 함수를 사용하면 cnt에 사전 자료형으로 리스트의 원소 개수를 세고 저장한다.
{'headgear' : 2, 'eyewear' : 1}처럼 cnt에 저장된다.
reduce는 위에 설명한 형태를 갖는다.
lambda는 간단한 함수를 표현하는데 적합하다.
lambda x, y: x * (y + 1)는 x와 y라는 변수를 사용하여 x * (y + 1)을 반환한다는 의미이다.
리스트는 방금 만든 사전 자료형의 values를 이용한다.
초기값은 처음에 대입되는 값이므로 초기값을 1로 둬야 계산이 알맞다.
그러면 x에는 1이 대입되고, 처음의 계산은 1 * (y+1)이 된다.
그리고 y+1이라는 결과에 나머지 원소들이 곱해진다.
마지막으로 -1을 빼면 계산이 끝난다.
ex) 예를 들어 리스트가 [2, 1]이고 초기값이 1, 함수가 x * (y + 1)이면 reduce의 결과는 다음과 같다.
1 * (2 + 1) = 3
3 * (1 + 1) = 6
여기서 1을 빼면 정답이 된다.
6 - 1 = 5
끝으로
되게 어려운 함수를 배우게 되었다..