
https://programmers.co.kr/learn/courses/30/lessons/72411
여러명의 손님이 시킨 메뉴조합중 조합 개수별로 인기가 제일 높은 조합을 고르는 문제다.
입력: [orders, course]
- orders: 2 이상 20이하의 배열길이
 
- 각 원소: 길이가 2 이상 10이하인 문자열
 
- 각 문자열은 대문자로만 이뤄져있음
 - 각 문자열은 같은 알파벳이 중복되자 않음
 - course: 1 이상 10 이하의 배열길이
 
- 각 원소: 길이가 2이상 10이하인 자연수가 오름차순 정렬돼있음
 
- 각 원소는 같은값이 중복되어 있지 않음
 
출력: 조합 개수별로 인기가 제일 높은 조합의 배열목록을 출력함
- 배열에 저장된 알파벳들은 오름차순으로 정렬되어있음.
 - 주문횟수가 같다면 같은 조합 모두 배열에 저장함
 - orders, course는 무조건 return하는 배열 길이가 1이상이 되도록 주어짐.
 
정답을 구하는 과정은 간단하다.
// 조합을 구하는 함수
function getCombination(input, end, start=0, result=[], tmp=[]) {
    if (tmp.length === end) {
        result.push(tmp);
        return;
    }
    for (let i=start; i<input.length; i++) {
        getCombination(input, end, i+1, result, [...tmp, input[i]]);
    }
    return result;
}
function solution(orders, course) {
    const resultCourse = {};
    const maxCntCombis = {};
    let result = [];
    // orders의 모든 조합을 계산함
    orders.forEach((order) => {
        // 매개변수로 넘어온 order문자열을 배열로 변환
        const orderArr = order.split("").sort();
        // 모든 course 순환
        course.forEach( (courseNum) => {
            // order배열의 course개 조합 
            // 문자열로 치환하고 1차원 배열로 바꿔줌
            const combis = getCombination(orderArr, courseNum)
                            .map( combi => combi.join(""));
            // reeulstCourse 객체에 해당 메뉴 조합을 주문한 횟수를 저장함
            combis.forEach( combi => {
                resultCourse[combi] = (resultCourse[combi] || 0) + 1;
            })
        });
    });
    // 계산한 조합에서 주문수가 가장 높은 조합만 저장함
    Object.entries(resultCourse).forEach( (v) => {
        const menuLength = v[0].length;
        const nowCombi = maxCntCombis[menuLength];
        const combi = v[0];
        const cnt = v[1];
        
        // 손님들이 두번 이상 주문한 메뉴라면
        if (cnt >= 2) {
            // 객체에 현재 조합이 있는경우
            if (nowCombi){
                // 객체에 저장된 조합보다 현재 조합의 주문횟수가 더 많은경우
                if (cnt > nowCombi.cnt) {
                    maxCntCombis[menuLength] = {
                        cnt,
                        combis: [combi]
                    }
                // 겍체에 저장된 조합과 현재 조합의 주문횟수가 같은경우
                }else if (cnt === nowCombi.cnt) {
                    maxCntCombis[menuLength].combis.push(combi);
                }
            } 
            // 객체에 현재 조합이 없는경우
            else {
                maxCntCombis[menuLength] = {
                    cnt,
                    combis: [combi]
                }
            }
        }
    });
    // 결과를 result에 저장함
    Object.entries(maxCntCombis).forEach ( (v) => {
        const combis = v[1].combis;
        combis.forEach ( (combi) => {
            result.push(combi);
        });
    });
    
    return result.sort();
}
const orders = ["ABCDE", "AB", "CD", "ADE", "XYZ", "XYZ", "ACD"]
const course = [2,3,5];
const a = solution(orders, course);
console.log(a);