본문 바로가기

알고리즘 문제풀이/프로그래머스 Level 1

[2024 KAKAO WINTER INTERNSHIP/JavaScript] 가장 많이 받은 선물

# 문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/258712

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

목차

 

카카오 문제 해설    2024 카카오 겨울 인턴십 코딩테스트 문제해설 링크
더보기

이 문제는 자료구조와 반복문, 조건문 등 프로그래밍의 기초 개념들을 적절히 활용하여 푸는 문제입니다.

N명의 이름 리스트에 인덱스를 붙이고 N×N 2차원 배열에 선물을 주고받은 횟수를 저장하는 방법으로 요구사항을 구현할 수 있습니다. 이름 리스트에 인덱스를 붙일 때, 언어에 따라 해시맵(HashMap) 등의 자료구조를 활용할 수 있고, 입력 사이즈가 작기 때문에 인덱스를 찾는 내장 함수를 사용하거나 반복문을 사용해 인덱스를 찾는 코드를 직접 구현해도 됩니다.

이를 위해, 각 gifts의 원소에서 선물을 준 사람 A와 받은 사람 B의 이름을 분리합니다. A의 인덱스가 i, B의 인덱스가 j라면 위에서 생성한 2차원 배열의 (i행, j열)의 값을 1 늘려 A가 B에게 보낸 선물의 수를 카운팅 할 수 있습니다. gifts의 모든 기록을 저장하면 A가 B에게 준 선물의 총 수는 배열의 (i행, j열)의 값, A가 모두에게 준 선물의 수는 배열의 i행의 합, A가 모두에게 받은 선물의 수는 배열의 i열의 합으로 구할 수 있습니다.

위 값들을 모두 구했다면 각 사람마다 자신을 제외한 N - 1명에게 선물을 몇 개 받는지 카운팅하고, 그 최댓값을 갱신해 문제의 정답을 구할 수 있습니다.

 

내 문제풀이
function solution(friends, gifts) {
    var answer = 0;
    var arr = []; // 2차원 배열
    var name_index = {}; // { 이름: arr 인덱스, }
    var presenet_index = []; // 선물지수 배열
    var total_get = new Array(friends.length).fill(0); // 다음달에 받는 선물 배열

    // 초기화
    for (var i=0; i<friends.length; i++) {
        arr[i] = new Array(friends.length).fill(0);
        name_index[friends[i]] = i;
    }

    // [준 사람, 받은 사람] 할당
    for (var str of gifts) {
        var names = str.split(' '); 
        arr[name_index[names[0]]][name_index[names[1]]]++;
    }

    // 선물지수: 준 선물의 수 - 받은 선물의 수
    for (var i=0; i<arr.length; i++) {
        presenet_index[i] = 0;
        for (var j=0; j<arr.length; j++) {
            presenet_index[i] += arr[i][j] - arr[j][i];
        }
    }

    // 다음달 선물 받기
    for (var i=0; i<arr.length; i++) {
        for (var j=i+1; j<arr.length; j++) {
            var give = arr[i][j];
            var get = arr[j][i];

            if (give > get) {
                total_get[i]++;
            } else if (give < get) {
                total_get[j]++;
            } else {
                // 선물지수가 큰 사람이 받음
                if (presenet_index[i] > presenet_index[j]) {
                    total_get[i]++;
                } else if (presenet_index[i] < presenet_index[j]) {
                    total_get[j]++;
                }
            }
        }
    }

    // 가장 선물을 많이 받는 사람
    for (var t of total_get) {
        if (t > answer) answer = t;
    }

    return answer;
}

프로그래머스 다른사람 풀이 참고 (nd098pkc / 링크)
function solution(friends, gifts) {
   const length = friends.length
   const giftPoints = new Array(length).fill(0)
   const index = {}
   const record = []
   const points = new Array(length).fill(0)
   for(let i=0;i<length;i++){
       record[i]=new Array(length).fill(0)
       index[friends[i]] = i
   }
   for(const gift of gifts){
       const [giver, taker] = gift.split(' ')
       record[index[giver]][index[taker]] +=1
       giftPoints[index[giver]] +=1
       giftPoints[index[taker]] -=1
   } 
   for(let i=0;i<length;i++){
       for(let j=0;j<length;j++){
           if(record[i][j]>record[j][i]){
               points[i]+=1
           } else if(record[i][j]===record[j][i]){
               if(giftPoints[i]>giftPoints[j]){
                   points[i]+=1
               }
           }
       }
   } 
    return Math.max(...points)
}

 

>> 내 풀이와의 차이점

1. 구조 분해 할당: 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식. 기억하자!

const [giver, taker] = gift.split(' ')

 

2. 내 풀이에 있는 [준 사람, 받은 사람] 할당과 선물지수 할당을 동시에 처리

 - 준 사람, 받은 사람 정보로 선물지수를 구할 수 있으니 한 번에 처리하는 게 효율적...! 당연한 건데 막상 풀 땐 생각을 못했다...

 

3. 다음달 선물받기 할당할 때 나는 한 번에 준 사람과 받은 사람을 처리하려고 했는데, 준 사람 기준으로 작업하면 else if 구문이 필요하지 않음. 코드가 길어지지 않는다는 장점...!

 

4. Math.max(): 정적 메서드는 매개변수로 주어진 숫자 중 가장 큰 수를 반환하거나, 매개변수가 없을 경우 -Infinity를 반환

 - 간단한 함수들은 기억해두면 코드의 가독성을 높이는 데 도움이 될 것 같음