본문 바로가기

Problem Solving

99클럽 코테 스터디 6일차 TIL - 프로그래머스 의상 JAVA 풀이

문제

🔗https://school.programmers.co.kr/learn/courses/30/lessons/42578

 

문제 접근

설명

 이 문제는 옷의 종류에 따라 조합할 수 있는 경우의 수를 구하는 문제입니다.

접근법

 코니가 종류 별로 입을 수 있는 옷의 가지 수는 "옷의 수 + 1" 입니다. 옷의 선택지 수에 아무것도 착용하지 않는 경우의 수 1을 더하기 때문입니다. 문제에서 주어진 예시로 설명하자면 얼굴에 착용할 수 있는 경우의 수는 안경, 선글라스, 착용 X 으로 3가지 입니다.

 

코니가 입을 수 있는 서로 다른 옷의 조합 수는 "종류 별 옷의 선택지 수"를 모두 곱한 뒤 "아무것도 입지 않는 경우 1"을 빼주면 됩니다. 문제 예시에서는 (2 + 1) x (1 + 1)  x (1 + 1)  x (1 + 1) - 1 = 23이 됩니다.

 

문제 풀이

class Solution {
    public int solution(String[][] clothes) {
        
        Map<String, Integer> map = new HashMap<>();

        for(String[] cloth : clothes) {
            String type = cloth[1];
            
            if (map.containsKey(type)) // 해당 종류가 이미 존재한다면
                map.replace(type, map.get(type) + 1); // 개수 + 1
            else
                map.put(type, 1);
        }

        return map.values().stream().reduce(1, (a, b) -> a * (b + 1)) - 1;
    }
}

 

 옷의 종류 별로 선택지 개수를 구하기 위해 Java의 컬렉션 프레임워크 중 Map 자료구조를 사용했습니다. Map의 key에는 옷의 종류를 저장하고, value에는 종류 별 선택지 수(옷의 수)를 저장했습니다.

 

코니가 입을 수 있는 의상 조합을 구하기 위해 Map의 values() 메서드와 스트림 api 중 reduce() 를 사용했습니다. values 메서드는 값들만 추출한 컬렉션을 반환합니다. reduce 메서드는 스트림의 모든 요소를 누적해 하나의 결과로 결합하는데 사용합니다.

 

Stream API 중 reduce

 

reduce의 첫 번째 인자 var1은 초기값을, 두 번째 인자 var2는 스트림의 각 요소를 처리할 람다식을 받습니다. 위 문제에서는 코니가 종류 별로 입을 수 있는 옷의 선택지 수들(values)에 대해 누적으로 곱셈을 해야합니다. 따라서 var1에는 초기값인 1을, var2에는 누적 곱셈하는 람다식을 작성합니다.

 

BinaryOperator
BiFunction

 

BinaryOperator 람다식은 BiFunction<T, T, T> 함수형 인터페이스를 상속했습니다. BiFunction의 메서드 apply는 두 개의 인자를 받아 하나의 결과를 반환합니다. 따라서 람다식은 다음과 같이 구현할 수 있습니다.

 

map.values().stream().reduce(1, (a, b) -> a * (b + 1)) - 1;

 

람다식에서 a는 지금까지의 스트림 요소들의 누적된 값을, b는 스트림의 현재 요소를 의미합니다. 즉, map의 각 요소들(= stream의 각 요소들)은 b자리에 차례로 들어가게 되고, 초기값 1 부터 누적으로 곱셈된 값은 a 자리에 들어가게 됩니다.

 

import java.util.Arrays;
import static java.util.stream.Collectors.*;

class Solution {
    public int solution(String[][] clothes) {
        
        return Arrays.stream(clothes)
                .collect(groupingBy(cloth -> cloth[1], mapping(cloth -> cloth[0], counting())))
                .values()
                .stream()
                .reduce(1L, (a, b) -> a * (b + 1)).intValue() - 1;
    }
}

 

Map 컬렉션을 사용하지 않고 스트림만 사용해 해결한 풀이도 있었습니다. 옷 종류로 grouping 한 뒤 숫자를 카운팅 하는 방법입니다.

 

정리

이 문제를 통해 조합을 구하는 방법을 알 수 있었고, Stream api 중 reduce 메서드를 활용해 누적 연산을 할 수 있음을 깨달았습니다.