프로그래머스 Lv.2 롤케이크 자르기
문제 설명
철수는 롤케이크를 두 조각으로 잘라서 동생과 한 조각씩 나눠 먹으려고 합니다. 이 롤케이크에는 여러가지 토핑들이 일렬로 올려져 있습니다. 철수와 동생은 롤케이크를 공평하게 나눠먹으려 하는데, 그들은 롤케이크의 크기보다 롤케이크 위에 올려진 토핑들의 종류에 더 관심이 많습니다. 그래서 잘린 조각들의 크기와 올려진 토핑의 개수에 상관없이 각 조각에 동일한 가짓수의 토핑이 올라가면 공평하게 롤케이크가 나누어진 것으로 생각합니다.예를 들어, 롤케이크에 4가지 종류의 토핑이 올려져 있다고 합시다. 토핑들을 1, 2, 3, 4와 같이 번호로 표시했을 때, 케이크 위에 토핑들이 [1, 2, 1, 3, 1, 4, 1, 2] 순서로 올려져 있습니다. 만약 세 번째 토핑(1)과 네 번째 토핑(3) 사이를 자르면 롤케이크의 토핑은 [1, 2, 1], [3, 1, 4, 1, 2]로 나뉘게 됩니다. 철수가 [1, 2, 1]이 놓인 조각을, 동생이 [3, 1, 4, 1, 2]가 놓인 조각을 먹게 되면 철수는 두 가지 토핑(1, 2)을 맛볼 수 있지만, 동생은 네 가지 토핑(1, 2, 3, 4)을 맛볼 수 있으므로, 이는 공평하게 나누어진 것이 아닙니다. 만약 롤케이크의 네 번째 토핑(3)과 다섯 번째 토핑(1) 사이를 자르면 [1, 2, 1, 3], [1, 4, 1, 2]로 나뉘게 됩니다. 이 경우 철수는 세 가지 토핑(1, 2, 3)을, 동생도 세 가지 토핑(1, 2, 4)을 맛볼 수 있으므로, 이는 공평하게 나누어진 것입니다. 공평하게 롤케이크를 자르는 방법은 여러가지 일 수 있습니다. 위의 롤케이크를 [1, 2, 1, 3, 1], [4, 1, 2]으로 잘라도 공평하게 나뉩니다. 어떤 경우에는 롤케이크를 공평하게 나누지 못할 수도 있습니다.
롤케이크에 올려진 토핑들의 번호를 저장한 정수 배열
topping
이 매개변수로 주어질 때, 롤케이크를 공평하게 자르는 방법의 수를 return 하도록 solution 함수를 완성해주세요.제한사항
- 1 ≤
topping
의 길이 ≤ 1,000,000
- 1 ≤
topping
의 원소 ≤ 10,000입출력 예
topping result [1, 2, 1, 3, 1, 4, 1, 2] 2 [1, 2, 3, 1, 4] 0
풀이 코드
function solution(topping) {
let oldBro = new Set(topping).size;
const youngBro = new Set();
let restToppings = topping.slice();
let result = 0;
const lastToppings = new Map();
new Set(topping).forEach((x) => lastToppings.set(x, topping.indexOf(x)));
for (let i = topping.length - 1; i >= 0; i--) {
let cutTopping = restToppings.pop();
youngBro.add(cutTopping);
if (i === lastToppings.get(topping[i])) oldBro--;
if (oldBro === youngBro.size) result++;
}
return result;
}
풀이 설명
- 시간초과로 인해 반복문 내 set을 사용하지 않고 pop()으로 롤케이크를 뒤에서 자른다. (shift()보다 pop()이 더 빠름)
function solution(topping) {
let oldBro = new Set(topping).size;
const youngBro = new Set();
let restToppings = topping.slice();
let result = 0;
const lastToppings = new Map();
new Set(topping).forEach((x) => lastToppings.set(x, topping.indexOf(x)));
//...
}
-
중복 토핑을 제외하고 토핑 수를 세기 위해
oldBro
(=철수)와youngBro
를 Set으로 생성한다.oldBro
와youngBro
는 철수와 동생이 롤케이크를 자르면서 가지는 토핑의 수를 나타낸다. -
restToppings
는 롤케이크를 뒤에서부터 자르면서 남는 토핑 배열이다.topping
은 for 문으로 순회할 것이므로 원본 배열의 요소 변경을 방지하기 위해 복사하여 할당한다. -
lastToppings
를 Map으로 생성하고 (key가 number 타입) 토핑별 첫 번째 인덱스값(뒤에서부터 잘랐을 때, 마지막으로 남은 토핑 위치)을 저장한다.
function solution(topping) {
//...
for (let i = topping.length - 1; i >= 0; i--) {
let cutTopping = restToppings.pop();
youngBro.add(cutTopping);
if (i === lastToppings.get(topping[i])) oldBro--;
if (oldBro === youngBro.size) result++;
}
return result;
}
-
oldBro
가 전체 롤케이크를 가지고 있고 롤케이크를 뒤에서부터 자르며youngBro
에 토핑을 준다. -
topping 전체를 거꾸로 순회하며 맨 뒤에 해당하는 토핑(=
restToppings
의 마지막 값)을youngBro
에 추가한다. Set으로 생성되어 있으므로 중복 값은 제외되고 고유 토핑만 남는다. -
롤케이크를 뒤에서부터 자르므로,
lastToppings
의 잘라 주려는 해당 토핑이 현재 인덱스와 동일하면 형이 가진 토핑에서도 -1씩 제거한다. -
동생의 고유 토핑 개수(
youngBro
)와 철수의 고유 토핑 개수(oldBro
)가 동일하면 결괏값을 증가시킨다.
References
프로그래머스 연습