본문 바로가기
👋국비 후기 모음👋 (이력도 확인 가능!)
개발/코테 준비

[JS] 프로그래머스 - 위장

by 킴뎁 2022. 2. 13.
728x90
반응형

내 풀이

function solution(clothes) {
    let answer = 1;
    let obj={};
    
    let keyMap = clothes.map(a => a[1]); 
    let keySet = new Set(keyMap);   
    let key = [...keySet];          
    
    for(let i=0; i<key.length; i++) {
        obj[key[i]] = 1;           
    }
    
    for(let i=0; i<key.length; i++) {
        for(let j=0; j<clothes.length; j++) {
            if(key[i] === clothes[j][1]) {  
                obj[key[i]]++;
            }
        }
    }
    
    for(let o in obj) {    
        answer *= obj[o]
    }
    
    return answer-1;   
}

 

해설

오랜만에 문제를 잡았다. 문제를 보고 어떻게 풀어야할지 감이 안와서 1시간 정도 고민하다가 결국 블로그를 참고했다.

이 문제는 결국 경우의 수를 구하면 되는 문제다.

각 의상의 종류별로 의상이 몇개인지 구한 후 각각의 경우를 모두 곱한 후 -1 해주면 된다.

 

예제 #1로 설명해 볼까한다. 보기 쉽게 한글로!

의상의 이름 의상의 종류
노란모자 모자
파란선글라스 안경
초록모자 모자

여기서 스파이가 위장할 수 있는 모든 경우의 수는 입출력 예 설명에 나와있듯이

  • 노란모자
  • 파란선글라스
  • 초록모자
  • 노란모자 + 파란선글라스
  • 초록모자 + 파란선글라스

총 5개의 경우가 나온다.

이를 공식화 해보자면

모자의 경우 2가지가 있고 안경은 1가지가 있다. 그리고 각각의 경우 착용을 안하는 경우의 수도 존재한다.

즉, 모자는 미착용, 노란모자, 파란모자 // 안경은 미착용, 파란선글라스 의 조합이 존재한다.

모자 3 x 안경 2의 경우의 수가 나오고 이 중에 둘 다 미착용인 경우의 수를 빼주면

3x2-1 = 5가지가 나오게 된다.

 

문제 설명에 나온 예제로 풀어본다면

얼굴 2 / 상의 1 / 하의 1 / 겉옷 1.

각각의 미착용 경우가 존재하므로 -> 얼굴 3 / 상의 2 / 하의 2 / 겉옷 2.

3x2x2x2-1 = 23의 경우가 존재한다.

 

나같은 경우엔 위의 해설을 본 후 코드를 작성했다.

어떻게 풀지 감이 안왔는데 막상 보니 단순 경우의 수 문제여서 조금 허탈한 감이 있었다.

이제 다 알았으니 코드를 작성하려고 했는데 생각보다 조금 막혔었다. 아직 갈 길이 멀다를 깨달았다.

이제 내 코드를 설명해본다.

** 예제 1을 예시로 설명

 

function solution(clothes) {
    let answer = 1;
    let obj={};
    let keyMap = clothes.map(a => a[1]);
    
    // console.log(keyMap) -> [ 'headgear', 'eyewear', 'headgear' ]
    
    // console.log(clothes); ->
    //    [
    //      [ 'yellow_hat', 'headgear' ],
    //      [ 'blue_sunglasses', 'eyewear' ],
    //      [ 'green_turban', 'headgear' ]
    //    ]
    
	...
    
    return answer-1; 
}

기본 문제는 answer = 0인데 1로 초기화 해놨다. 이 부분은 밑에서 설명하겠다.

obj는 각 의상의 종류별로 몇가지의 의상이 존재하는 지를 담는 객체이다.

keyMap은 주어진 clothes의 key 즉, 의상의 종류만 뽑아서 담는 변수이다.

clothes에  map()을 이용하여 keyMap에 담아주었다.

 

function solution(clothes) {

	...
    
    // console.log(keyMap) -> [ 'headgear', 'eyewear', 'headgear' ]
    
    let keySet = new Set(keyMap);   // Set으로 중복제거
    let key = [...keySet];          // Set -> Array (Spread Operator 전개연산자 사용)
    
    // console.log(keySet); -> Set { 'headgear', 'eyewear' }
	// console.log(key);    -> [ 'headgear', 'eyewear' ]
    
    ...
    
    return answer-1;    // 모든 경우의 수 중에 전부 다 안 입는 경우 1을 뺀다.
}

위의 주석으로 설명이 될 것이라 생각된다.

Set으로 중복 제거를 한 후 다시 Array로 바꿔준다. 여기서 처음으로 전개연산자(...)라는 걸 알게 되었다.

반응형

 

function solution(clothes) {
    
    ...
    
    // console.log(keySet); -> Set { 'headgear', 'eyewear' }
	// console.log(key);    -> [ 'headgear', 'eyewear' ]    
    
    for(let i=0; i<key.length; i++) {
        obj[key[i]] = 1;           
    }
  	
    // console.log(obj); -> { headgear: 1, eyewear: 1 }
    
	...
  
    return answer-1;    // 모든 경우의 수 중에 전부 다 안 입는 경우 1을 뺀다.
}

이제 obj에 해시 형식으로 넣어주도록 해보자.

obj[key[i]] = 1; -> key [ 'headgear', 'eyewear' ]

-> obj['headgear'] = 1, obj['eyewear'] = 1.

앞선 설명에 따라 미착용의 경우의 수 1을 default로 넣어준다.

 

function solution(clothes) {
	
    ...
    
    // console.log(key); -> [ 'headgear', 'eyewear' ]
    // console.log(clothes); ->
    //    [
    //      [ 'yellow_hat', 'headgear' ],
    //      [ 'blue_sunglasses', 'eyewear' ],
    //      [ 'green_turban', 'headgear' ]
    //    ]
    
    for(let i=0; i<key.length; i++) {
        for(let j=0; j<clothes.length; j++) {
            if(key[i] === clothes[j][1]) {
                obj[key[i]]++;
            }
        }
    }
    
    // console.log(obj); -> { headgear: 3, eyewear: 2 }
    
	...
    
    return answer-1;    // 모든 경우의 수 중에 전부 다 안 입는 경우 1을 뺀다.
}

key와 의상의 종류가 일치한다면 해당 키의 개수를 늘려주는 코드이다. -> obj[key[i]]++;

 

function solution(clothes) {
	
    ...
    
    // console.log(obj); -> { headgear: 3, eyewear: 2 }
    
    for(let o in obj) {     // 문제의 핵심. 경우의 수를 이용하여 곱한다.
        answer *= obj[o]
    }
    
    return answer-1;    // 모든 경우의 수 중에 전부 다 안 입는 경우 1을 뺀다.
}

이제 다 왔다. 향상된 for문 연습겸 이용했다. 위의 코드에서 o는 각각 headgear와 eyewear를 나타낸다.

obj['headgear'] = 3, obj['eyewear'] = 2 -> answer에 곱한다. answer가 0일 경우 곱할 수가 없다.

그러므로 처음 answer 초기화를 1로 주었다.

마지막에 전부 미착용인 경우의 수 1을 빼주면 끝!


다른 사람 풀이

function solution(clothes) {
    let answer = 1;
    const obj = {};
    for(let arr of clothes) {
        obj[arr[1]] = (obj[arr[1]] || 0) + 1;
    }

    for(let key in obj) {
        answer *= (obj[key]+1);
    }

    return answer - 1;
}

나와 같은 방식의 코드를 리팩토링한 버전이라 할 수 있다.

다른 풀이로는 reduce()를 쓴 방식이 있는데 그 코드는 이해를 하지 못해서 공부의 필요성을 느꼈다.

위의 코드의 ||를 잘 몰라서 해석하는데 어려움을 겪었었다. 단순히 생각하면 obj[arr[1]]이 없다면 0이 default라는 소리이다.


요즘 리액트의 재미를 느껴서 js를 공부해보고자 코테 언어를 js로 채택했다.

막상 해보려니까 문법 공부의 필요성을 느끼게 되었다.

 

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

 

코딩테스트 연습 - 위장

 

programmers.co.kr

반응형
👋국비 후기 모음👋 (이력도 확인 가능!)

댓글