
21. sales event
Sunhyup Lee. (2024). To be a successful candidate for the coding test. goldenrabbit. p.251.
Problem solving
문제 이해
1. 입력값 설명
- want: 정현이가 원하는 제품의 이름이 담긴 배열 (예: [‘바나나’, ‘사과’, ‘쌀’])
- number: 각 제품별로 정현이가 원하는 수량(예: [3, 2, 1])
- discount: 할인중인 제품 리스트가 날짜별로 순서대로 담겨 있음(예: [‘치킨, ‘사과, ‘바나나’…])
2. 문제 조건
- XYZ 마트에서 매일 1가지 제품이 할인됩니다.
- 할인 상품베열(
discount
)에서 정현이가 원하는 모든 제품과 수량이 정확히 일치하는 10일 연속 구간을 찾아야 합니다. - 정현이가 원하는 제품과 수량이 일치하지 않으면 회원가입을 하지 않으며, 가능한 날이 없으면
0
을 반환합니다.
3. 목표
- 할인 목록에서 10일 연속 구간을 순회하며, 해당 구간의 할인 상품들이
want
,number
조건을 만족하는 지를 확인합니다. - 조건에 맞는 구간이 몇 개 있는지 반환합니다.
4. 풀이요약
- 할인 목록(discount)의 모든 10일 구간을 순회
- 각 구간에서 제품과 수량이
want
와number
조건을 만족하는지 검사 - 조건을 만족하면 카운트 증가
- 모든 구간을 확인한 뒤 카운트를 반환
function solution(want, number, discount) {
// 1. 원하는 제품과 수량을 딕셔너리 형태로 저장
const wantMap = {};
for (let i = 0; i < want.length; i++) {
wantMap[want[i]] = number[i];
}
// 2. 슬라이딩 윈도우 크기와 결과 변수 초기화
const windowSize = 10;
let count = 0;
// 3. 현재 윈도우의 제품 개수를 저장할 딕셔너리
const currentWindow = {};
// 4. 초기 윈도우 설정 (첫 번째 10일)
for (let i = 0; i < windowSize; i++) {
const product = discount[i];
currentWindow[product] = (currentWindow[product] || 0) + 1;
}
// 5. 맵 비교 함수 (wantMap과 currentWindow가 같은지 확인)
const isMatch = (map1, map2) => {
for (const key in map1) {
if (map1[key] !== map2[key]) return false;
}
return true;
};
// 6. 첫 번째 윈도우 검사
if (isMatch(currentWindow, wantMap)) {
count++;
}
// 7. 슬라이딩 윈도우 이동 (한 칸씩 옮기면서 검사)
for (let i = windowSize; i < discount.length; i++) {
// 윈도우에서 빠지는 값 제거
const outgoing = discount[i - windowSize];
currentWindow[outgoing]--;
if (currentWindow[outgoing] === 0) {
delete currentWindow[outgoing];
}
// 윈도우에 새로 들어오는 값 추가
const incoming = discount[i];
currentWindow[incoming] = (currentWindow[incoming] || 0) + 1;
// 현재 윈도우가 조건을 만족하는지 확인
if (isMatch(currentWindow, wantMap)) {
count++;
}
}
return count;
}
1단계: 원하는 제품과 수량을 딕셔너리에 저장
wnat
와 number
배열을 사용해 정현이가 원하는 제품과 개수를 딕셔너리 형태로 만든다.
const want = ["banana", "apple", "rice", "pork"];
const number = [3, 2, 2, 1];
이를 딕셔너리로 저장하면
const wantMap = {
banana: 3,
apple: 2,
rice: 2,
pork: 1,
};
이제 wantMap
은 정현이가 원하는 조건을 담고 있습니다.
2단계: 슬라이딩 윈도우 설정
-
슬라이딩 윈도우 크기는 문제에서 주어진 “연속된 10일”을 의미합니다. 따라서,
windowSize = 10
으로 설정합니다. -
count
변수는 조건을 충족하는 연속된 10일의 횟수를 셀 때 사용합니다. 처음에는count = 0
으로 초기화 합니다.
3단계: 첫번째 10일의 제품 개수 계산
- 할인 목록인
discount
배열의 첫 번째 10일을 기준으로, 각 제품의 개수를 세어 저장합니다. - 이 때,
currentWindow
라는 딕셔너리를 사용해 현재 10일 동안의 제품 개수를 추적합니다.
예를 들어, 다음과 같은 discount
배열이 있다고 가정합시다.
const discount = [
"chicken",
"apple",
"apple",
"banana",
"rice",
"pork",
"banana",
"banana",
"banana",
"apple",
];
여기서 첫번째 10일을 계산하면
currentWindow = {
chicken: 1,
apple: 3,
banana: 4,
rice: 1,
pork: 1,
};
이 작업은 루프를 돌며 각 제품의 개수를 세어서 currentWindow
에 저장합니다.
4단계: 두 딕셔너리 비교 함수
wantMap
과currentWindow
가 같은지 확인하기 위해,isMatch
라는 함수를 정의합니다.
const isMatch = (map1, map2) => {
for (const key in map1) {
if (map1[key] !== map2[key]) return false;
}
return true; // 조건 충족
};
map1
(wantMap)의 모든 키를 확인하며,map2
(currentWindow)와 각 값이 동일한지 비교합니다.- 값이 하나라도 다르면
false
, 모두 같은면true
를 반환합니다.
5단계: 첫번째 윈도우 검사
- 첫 번째 10일(
currentWindow
)이 정현이의 조건(wantMap
)을 만족하는지 확인합니다.
if (isMatch(currentWindow, wantMap)) {
count++;
}
만약 첫번째 윈도우가 조건을 만족하면, count
를 1 증가시킵니다.
6단계: 슬라이딩 윈도우
이제 discount
배열에서 윈도우를 한 칸 씩 옮기면서 조건을 확인합니다.
(1) 윈도우에서 빠지는 값 제거
- 윈도우가 한 칸 이동하면, 맨 앞의 값(윈도우에서 나가는 값)을 제거합니다.
const outgoing = discount[i - windowSize];
currentWindow[outgoing]--;
if (currentWindow[outgoing] === 0) {
delete currentWindow[outgoing]; // 개수가 0이면 삭제
}
(2) 새로 들어오는 값 추가
- 윈도우의 오른쪽으로 새로 들어오는 값을 추가합니다.
const incoming = discount[i];
currentWindow[incoming] = (currentWindow[incoming] || 0) + 1;
(3) 조건 확인
- 새로 갱신된
currentWindow
가 조건(wantMap
)을 만족하는지 확인합니다.
if (isMatch(currentWindow, wantMap)) {
count++;
}
7단계: 최종 결과 반환
- 조건을 충족한 구간의 개수(
count
)를 반환합니다.