문제 설명
스파이들은 매일 다른 옷을 조합하여 입어 자신을 위장합니다.
예를 들어 스파이가 가진 옷이 아래와 같고 오늘 스파이가 동그란 안경, 긴 코트, 파란색 티셔츠를 입었다면 다음날은 청바지를 추가로 입거나 동그란 안경 대신 검정 선글라스를 착용하거나 해야 합니다.
종류이름얼굴 | 동그란 안경, 검정 선글라스 |
상의 | 파란색 티셔츠 |
하의 | 청바지 |
겉옷 | 긴 코트 |
스파이가 가진 의상들이 담긴 2차원 배열 clothes가 주어질 때 서로 다른 옷의 조합의 수를 return 하도록 solution 함수를 작성해주세요.
제한사항
- clothes의 각 행은 [의상의 이름, 의상의 종류]로 이루어져 있습니다.
- 스파이가 가진 의상의 수는 1개 이상 30개 이하입니다.
- 같은 이름을 가진 의상은 존재하지 않습니다.
- clothes의 모든 원소는 문자열로 이루어져 있습니다.
- 모든 문자열의 길이는 1 이상 20 이하인 자연수이고 알파벳 소문자 또는 '_' 로만 이루어져 있습니다.
- 스파이는 하루에 최소 한 개의 의상은 입습니다.
입출력 예
[["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
예제 #2
face에 해당하는 의상이 crow_mask, blue_sunglasses, smoky_makeup이므로 아래와 같이 3개의 조합이 가능합니다.
1. crow_mask
2. blue_sunglasses
3. smoky_makeup
문제 풀이
같은 Hash를 사용한 문제인 '완주하지 못한 선수'라는 문제를 풀었다면 비교적 쉽게 풀 수 있는 문제이다.
HashMap 을 만들어 의상 부위 카테고리를 key 값으로 두고 의상종류의 갯수를 value로 만들어주었다.
그리고 이후 경우의 수를 계산하여 반환하여 문제를 해결하였다.
Code
import java.util.HashMap;
import java.util.Iterator;
class Solution {
public int solution(String[][] clothes) {
// 1. HashMap 만들기
HashMap<String, Integer> closet = new HashMap<>(); // 옷장 HashMap 생성
for (String[] clothe : clothes) { // 주어진 배열을 이용하여 Hashing
String type = clothe[1]; // [옷 이름, 옷 종류] 의 형태로 배열이 주어지므로 배열[1] == 옷 종류
closet.put(type, closet.getOrDefault(type, 0) + 1);
//getOrDefault를 이용하여 Hashing
}
// 2. 경우의 수 계산하기
int answer = 1; // 정답출력용 int 선언 (곱연산 예정이므로 초기값 1)
Iterator<Integer> allItems = closet.values().iterator();
while (allItems.hasNext()) {
answer *= allItems.next().intValue() + 1;
}
// 3. 정답 반환
return answer - 1; // 아무것도 입지 않은 경우를 뺌
// closet 생성 확인용
// Set<String> keySet = closet.keySet();
// for (String key : keySet) {
// System.out.println(key + " : " + closet.get(key));
// }
}
}
public class Main {
public static void main(String[] args) {
// String[][] exLis = {{"yellow_hat", "headgear"}, {"blue_sunglasses", "eyewear"}, {"green_turban", "headgear"}};
String[][] exLis = {{"crow_mask", "face"}, {"blue_sunglasses", "face"}, {"smoky_makeup", "face"}};
Solution action = new Solution();
System.out.println("action.solution(exLis) = " + action.solution(exLis));
}
}
(colorscripter 오류로 코드가 깨져 Tistory내부 코드첨부툴을 이용했다)
상세 풀이
- HashMap 선언 및 Hashing
의상들의 집합으로 만들어지므로 closet 이라고 이름을 정의해주었다.
이후 foreach문을 사용하여 주어진 배열을 Hashing 하였는데 자세히 설명하자면,
주어진 2차원 배열은 [[옷, 옷의 종류], [옷2, 옷의 종류2], ...] 이런 식으로 주어지므로 data가 포함된 배열의 1번 index에는 고정적으로 옷의 종류를 나타내는 문자열이 들어있다.
이 점을 이용하여 문제에서 주어진 배열 clothes속 배열들을 하나씩 꺼내어 String[] clothe 로 정의해주며 반복문을 돌도록 코드를 작성했다. 그리고 옷의 종류를 나타내는 clothe[1]를 type 변수를 정의하여 넣어주었고, {key(옷) : value(옷의 종류)} 형식으로 처음에 선언한 closet HashMap에 담아주었다.
이때 Map 클래스의 getOrDefault(Object key, V DefaultValue) 메소드를 사용하였다.
getOrDefault 메소드는
찾는 키가 존재한다면 해당 키의 값을 반환하고, 없다면 지정한 기본 값을 반환하는 메소드이다.
위 코드에서는 closet.getOrDefault(type, 0) + 1) 라고 작성되었으므로
closet HashMap내부에 type(옷 종류)과 같은 key가 존재한다면 해당 key의 value를 가져와 + 1을 하여 카운팅을 해주거나,
key(type)이 존재하지 않는다면 default값인 0에 + 1 더해준다.
default를 0으로 설정한 이유:
getOrDefault()를 사용함에 있어서 불가피하기 때문.
key값이 이미 존재한다면 value에 1을 더해 카운팅 해주어야 하므로 코드의 마지막에 '+ 1'이 꼭 들어가야 한다.
따라서 default 값을 1이 아닌 0으로 두어야 처음 발견한 type에 대하여 value값을 1로 HashMap에 등록할 수 있다.
따라서 closet.put(type, closet.getOrDefault(type, 0) + 1); 이라는 한 줄의 코드를 이용하여
옷의 종류 key로 지정하여 value로 해당 종류의 옷을 카운팅할 수 있게 되는 것이다.
- 경우의 수 계산하기
위 forEach문을 통해 모든옷의 종류에 count가 되어있는 HashMap을 얻었다.
이제 경우의 수를 구하는 공식에 따라 answer에 답을 정의한다.
먼저 int answer를 1로 선언해준다. (이유 : 곱연산 할 것이므로 0으로 선언할 시 원하는 결과를 낼 수 없음)
경우의 수 계산에는 Iterator함수를 이용했는데,
Iterator란 컬렉션 프레임워크(List, Set, Map, Queue 등)에서 값을 가져오거나 삭제할때 사용하는 함수로
모든 컬렉션 프레임워크에 공통으로 사용할 수 있고, 쉽게 값을 가져오거나 삭제할 수 있으며, 단 3개의 대표메소드만 숙지하고 있다면 사용하기 편리하다는 점 때문에 유용하게 쓰인다. 하지만 처음부터 끝까지 단방향 반복만 가능하고, 값을 변경하거나 추가하는 것이 불가능하며, 대량의 데이터를 제어할 때 속도가 느리다는 단점도 존재한다.
3개의 대표메소드는 다음과 같다.
Iterator.hasNext() - Iterator 안에 다음 값이 들어있는지 확인 들었으면 true, 안들었음 false
Iterator.next() - iterator의 다음 값 가져오기
Iterator.remove() - iterator에서 next() 시에 가져왔던 값을 컬렉션(List, Set, Map) 등에서 삭제. (반드시 next() 후에 사용해야 함)
while문을 이용하여 closet에서 값을 읽어올 수 있을만큼 반복하기위해 Iterator를 사용했다.
(사실 배운걸 까먹고 싶지 않아서 사용했다.)
closet에 들어있는 value값들을 hasNext()와 next()를 이용하여 순서대로 불러와 곱해주기만 하면 되는데
이때 주의할 점이 모든 카테고리에 대하여 입지 않는다는 선택지가 존재하므로 1을 더하여 곱해준다.
hasNext() = boolean 타입으로 반환
next() = Iterator의 다음 요소의 값으로 반환
- 정답 반환하기
마지막으로 answer를 반환해주기만 하면 정답이지만
문제의 조건에서 아무것도 입지 않는다는 선택지는 허용하지 않는다.
경우의 수 계산 당시 입지 않는다는 선택지를 추가하여 계산하였으므로!
모두 입지 않는다는 선택지 1개를 삭제해준 후 반환하면 정답을 반환하게 된다.
프로그래머스 제출 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import java.util.HashMap;
import java.util.Iterator;
class Solution {
public int solution(String[][] clothes) {
HashMap<String, Integer> closet = new HashMap<>();
for (String[] clothe : clothes) {
String type = clothe[1];
closet.put(type, closet.getOrDefault(type, 0) + 1);
}
int answer = 1;
Iterator<Integer> allItems = closet.values().iterator();
while (allItems.hasNext()) {
answer *= allItems.next().intValue() + 1;
}
return answer - 1;
}
}
|
cs |
출처
킹스맨 짤 : https://www.pinterest.co.kr/pin/556264991450818882/
문제풀이 참고 : 개발자로 취직하기.Tistory
'Learn > 프로그래머스' 카테고리의 다른 글
프로그래머스/Java) 전화번호 목록 (0) | 2022.07.11 |
---|---|
프로그래머스/Python) 완주하지 못한 선수 (0) | 2022.07.11 |