2021 카카오 블라인드 테스트 문제다. Map자료구조와 조합을 통해서 접근한다.
- 코스에 들어갈 음식의 숫자별로 반복문을 실행한다.
 - 손님의 주문 목록별로 사전순 정렬된 메뉴 조합을 만들고 개수를 카운팅한다.
 - 2에서 카운팅한 메뉴 조합 중 가장 많이 카운트된 조합들을 answer 목록에 추가한다.
 - 다시한번 answer 목록을 정렬한다.
 
import java.util.*;
class Solution {
    
    // 조합을 저장할 hashMap
    Map<String, Integer> map = new HashMap<>();
    
    // answer를 저장할 리스트
    ArrayList<String> answerList = new ArrayList<>();
    
    public String[] solution(String[] orders, int[] course) {    
    	// course에 사용될 음식의 개수별로 반복문을 실행합니다.
        for(int i = 0 ; i<course.length; i++){
        	
            // 주문 목록만큼 반복문을 실행합니다.
            for(int j = 0 ; j<orders.length; j++){
                String foods = orders[j];
                // 각 음식별로 조합 실행
                combi(course[i], 0, 0, foods, new StringBuilder());
            }
            // 최대값 변수 선언
            int max = 0;
            // map의 value들 중 가장 큰 값을 찾아줍니다.
            for(Integer value : map.values()){
                max = Math.max(max, value);
            }
            
            // 문제의 조건인 코스로 포함된 횟수의 최대값이 2번 이상인 경우
            if(max>=2){
            	// value가 최대값인 key들을 answer 목록에 추가해줍니다.
                for( String key : map.keySet() ){
                    if(map.get(key) == max){
                        answerList.add(key);
                    }
                }
            }
            
            // 다음 코스요리 조합을 실행하기 전에 map을 비워줍니다.
            map.clear();
        }
        // 사전순 정렬
        Collections.sort(answerList);      
        // List를 array로 변경해 리턴합니다.
        return answerList.toArray(new String[answerList.size()]);
    }
    
    /* 
    	end = 코스의 길이(메뉴의 개수), depth = 추가된 메뉴의 개수, sIndex = 조합이 시작될 인덱스
        foods = 조합에 사용될 주문 목록, course = 조합을 저장할 변수
    */
    public void combi( int end, int depth, int sIndex, String foods, StringBuilder course ){
    	// 메뉴가 코스의 정해진 길이만큼 추가 됐다면 종료
        if(depth == end){
        	// 정렬을 위한 charArray변환
            char[] arr = course.toString().toCharArray();
            // 사전순 정렬
            Arrays.sort( arr );
            // String으로 변환한 뒤 map에 추가
            String result = String.valueOf(arr);
            map.put(result, map.getOrDefault(result, 0)+1);
        }
        
        // 조합
        for(int i = sIndex; i<foods.length(); i++){
            combi(end, depth+1, i+1, foods, course.append(foods.charAt(i)));
            course.deleteCharAt(course.length()-1);
        }
    }
}
String의 불변 속성 때문에 StringBuilder를 써줘야 훨씬 효율적이다. 첫 제출에선 귀찮다는 이유로 String과 + 연산자를 썼다가 3점을 받아버렸다.. 해당 제출에서는 평균 실행 시간이 25ms정도에 느린 경우 50ms도 초과했으나, StringBuilder로 변환한 뒤에는 평균 10ms 내외로 크게 줄었다. 점수도 18점으로 상승한 건 덤.
귀찮아도 지킬 건 지키자.