diff --git a/src/programmers/Lv_1/README.md b/src/programmers/Lv_1/README.md index 785d2631..f60db4f3 100644 --- a/src/programmers/Lv_1/README.md +++ b/src/programmers/Lv_1/README.md @@ -80,4 +80,4 @@ | 76 | [바탕화면 정리](./desktopClean.js) | 23.05.15 | O | | 77 | [공원 산책](./park.js) | 23.09.19 | O | | 78 | [붕대 감기](./band.js) | 24.01.09 | △ | -| 79 | [가장 많이 받은 선물](./takeGiftsNums.js) | 24.01.10 | +| 79 | [가장 많이 받은 선물](./takeGiftsNums.js) | 24.01.15 | O | diff --git a/src/programmers/Lv_1/takeGiftsNums.js b/src/programmers/Lv_1/takeGiftsNums.js index afe9d7b7..97466bc6 100644 --- a/src/programmers/Lv_1/takeGiftsNums.js +++ b/src/programmers/Lv_1/takeGiftsNums.js @@ -1,43 +1,60 @@ +/** + * [구현] + * - 서로 주고받은 선물 수를 기록하려면 N * N의 2차원 배열이 필요하다. 해당 문제의 N(= frineds 수)은 50이므로 완전탐색이 가능하다. + * - 헷갈릴 수 있으나 다음달에 받을 선물의 개수를 셀 때, 선물 지수가 선물 횟수가 작은 사람 것을 빼앗아서 주는게 아니다. + */ + function solution(friends, gifts) { - const len = friends.length; - const nameMap = new Map(); - const giftTable = new Array(len).fill(0).map((_) => new Array(len).fill(0)); - const rankInfo = new Array(len).fill(0); - const nextMonth = new Array(len).fill(0); - - // 친구들 키 값 저장. - friends.forEach((name, idx) => { - nameMap.set(name, idx); - }); - - // 선물 주고받은 내역 기록 - gifts.forEach((info) => { - const [from, to] = info.split(" "); - giftTable[nameMap.get(from)][nameMap.get(to)]++; - }); - - // 기록을 바탕으로 선물 지수 계산 - for (let i = 0; i < len; i++) { - rankInfo[i] = giftTable[i].reduce((acc, cur) => (acc += cur), 0); - - for (let j = 0; j < len; j++) { - rankInfo[i] -= giftTable[j][i]; + // 이름과 인덱스 번호 매칭 Map + const N = friends.length; + const nameIndexMap = new Map(); + for (let i = 0; i < N; i++) { + nameIndexMap.set(friends[i], i); + } + + // 주고받은 선물 내역을 기록할 grid 선언 + const giftsGrid = Array.from({ length: N }, () => Array(N).fill(0)); + + // 선물 지수 계산 + const giftsRatio = Array.from({ length: N }, () => 0); + + // 다음 달 선물 예정 + const nextMonth = Array.from({ length: N }, () => 0); + + // 1. 선물 주고받은 횟수 카운트하기 + for (let i = 0; i < gifts.length; i++) { + let [from, to] = gifts[i].split(" "); + giftsGrid[nameIndexMap.get(from)][nameIndexMap.get(to)] += 1; + } + + // 2. 선물 지수 계산하기 + for (let i = 0; i < N; i++) { + // 총 선물한 수 세기 (가로) + giftsRatio[i] = giftsGrid[i].reduce((acc, current) => (acc += current), 0); + + // 선물 받은 수 빼기 (세로) + for (let j = 0; j < N; j++) { + giftsRatio[i] -= giftsGrid[j][i]; } } - // 다음 달 받을 선물 계산 - for (let i = 0; i < len; i++) { - for (let j = i + 1; j < len; j++) { - if (i === j) continue; - if (giftTable[i][j] > giftTable[j][i]) nextMonth[i]++; - if (giftTable[i][j] < giftTable[j][i]) nextMonth[j]++; - if (giftTable[i][j] === giftTable[j][i]) { - if (rankInfo[i] > rankInfo[j]) nextMonth[i]++; - if (rankInfo[i] < rankInfo[j]) nextMonth[j]++; + // 3. 다음달에 받을 선물 수 카운팅 + for (let i = 0; i < N; i++) { + for (let j = i + 1; j < N; j++) { + // j가 0부터 시작할 경우, 중복이 발생한다. + if (i === j) continue; // 자기 자신인 경우는 pass + + // 더 많이 선물한 사람이 다음달에 선물 하나를 받음 + if (giftsGrid[i][j] > giftsGrid[j][i]) nextMonth[i]++; + if (giftsGrid[i][j] < giftsGrid[j][i]) nextMonth[j]++; + + // 선물을 주고 받은 기록이 없거나 같은 경우 + if (giftsGrid[i][j] === giftsGrid[j][i]) { + if (giftsRatio[i] > giftsRatio[j]) nextMonth[i]++; + if (giftsRatio[i] < giftsRatio[j]) nextMonth[j]++; } } } - // 최댓값 반환 return Math.max(...nextMonth); }