일렬로 나열된 n개의 풍선이 있습니다. 모든 풍선에는 서로 다른 숫자가 써져 있습니다. 당신은 다음 과정을 반복하면서 풍선들을 단 1개만 남을 때까지 계속 터트리려고 합니다.
여기서 조건이 있습니다. 인접한 두 풍선 중에서 번호가 더 작은 풍선을 터트리는 행위는 최대 1번만 할 수 있습니다. 즉, 어떤 시점에서 인접한 두 풍선 중 번호가 더 작은 풍선을 터트렸다면, 그 이후에는 인접한 두 풍선을 고른 뒤 번호가 더 큰 풍선만을 터트릴 수 있습니다.
당신은 어떤 풍선이 최후까지 남을 수 있는지 알아보고 싶습니다. 위에 서술된 조건대로 풍선을 터트리다 보면, 어떤 풍선은 최후까지 남을 수도 있지만, 어떤 풍선은 무슨 수를 쓰더라도 마지막까지 남기는 것이 불가능할 수도 있습니다.
일렬로 나열된 풍선들의 번호가 담긴 배열 a가 주어집니다. 위에 서술된 규칙대로 풍선들을 1개만 남을 때까지 터트렸을 때 최후까지 남기는 것이 가능한 풍선들의 개수를 return 하도록 solution 함수를 완성해주세요.
a[i]는 i+1 번째 풍선에 써진 숫자를 의미합니다.| a | result |
|---|---|
[9,-1,-5] |
3 |
[-16,27,65,-2,58,-92,-71,-68,-61,-33] |
6 |
입출력 예 #1
[9, -1, -5] 에서 -1, -5가 써진 풍선을 고른 뒤, -1이 써진 풍선(번호가 더 큰 것)을 터트립니다.[9, -5] 에서 9, -5가 써진 풍선을 고른 뒤, -5가 써진 풍선(번호가 더 작은 것)을 터트립니다.[9, -1, -5] 에서 9, -1이 써진 풍선을 고른 뒤, 9가 써진 풍선(번호가 더 큰 것)을 터트립니다.[-1, -5] 에서 -1, -5가 써진 풍선을 고른 뒤, -5가 써진 풍선(번호가 더 작은 것)을 터트립니다.[9, -1, -5] 에서 9, -1이 써진 풍선을 고른 뒤, 9가 써진 풍선(번호가 더 큰 것)을 터트립니다.[-1, -5] 에서 -1, -5가 써진 풍선을 고른 뒤, -1이 써진 풍선(번호가 더 큰 것)을 터트립니다.입출력 예 #2
처음에 문제가 잘 이해되지 않아 접근법을 여기저기서 찾아보았지만 이해되는 풀이를 찾지 못해 제 기준 이해가 가장 잘 된 접근법을 공유하려 합니다.
이 문제의 핵심 규칙은 다음과 같습니다.
좌우 중 한 쪽에 자신보다 작은 풍선이 없다면 끝까지 살아남을 수 있다.
다시 말해, 좌우 양쪽에 자신보다 작은 풍선이 있다면 끝까지 살아남을 수 없다.
이것이 무슨 의미일까요?
먼저 풍선이 살아남을 수 없는 경우를 살펴봅시다. 문제의 조건에 따르면 인접한 두 풍선 중에서 번호가 더 작은 풍선을 터트리는 행위는 최대 1번만 할 수 있기 때문에, 왼쪽에도 자신보다 작은 풍선이 있고 오른쪽에도 자신보다 작은 풍선이 있는 경우 풍선은 반드시 터지게 됩니다.

-2번 풍선 기준 예시입니다.
그럼 어떻게 해야 풍선이 살아남을 수 있을까요? 왼쪽이나 오른쪽 중 한 쪽에 자신보다 작은 풍선이 없어야 살아남을 수 있습니다.

-71번 풍선 기준 예시입니다.
즉, 배열 a에 있는 어떤 풍선 a[i]을 기준으로 왼쪽에 있는 풍선들 중 최솟값, 오른쪽에 있는 풍선들 중 최솟값을 확인해서 왼쪽에도 a[i]보다 작은 풍선이 있고 오른쪽에도 a[i]보다 작은 풍선이 있는 경우를 제외하면 되는 것입니다.
따라서 다음과 같이 풀이를 진행할 수 있습니다.
left 배열을 생성하고, i번째 풍선을 포함하여 왼쪽에 있는 풍선들 중 가장 작은 풍선을 기록합니다. i번째 풍선 왼쪽에 left[i]보다 작은 풍선은 없으므로, left[i]에 기록된 값은 끝까지 살아남을 수 있는 풍선임을 의미합니다.

let left = Array(len);
left[0] = a[0];
for (let i = 1; i < len; i++) {
left[i] = Math.min(left[i - 1], a[i]);
}
마찬가지로 right 배열을 생성하고, i번째 풍선을 포함하여 오른쪽에 있는 풍선들 중 가장 작은 풍선을 기록합니다. i번째 풍선 오른쪽에 right[i]보다 작은 풍선은 없으므로, right[i]에 기록된 값은 끝까지 살아남을 수 있는 풍선임을 의미합니다.

let right = Array(len);
right[len - 1] = a[len - 1];
for (let i = len - 2; i >= 0; i--) {
right[i] = Math.min(right[i + 1], a[i]);
}
따라서
이 두 가지 조건 중 하나만 만족하면 살아남을 수 있는 풍선이 되므로, 이 두 집합의 중복을 제거한 합집합을 계산하기 위해 집합 자료형 Set을 이용하여 살아남을 수 있는 풍선의 수를 계산할 수 있습니다.
new Set([...left, ...right]).size;
전체 코드는 다음과 같습니다.
function solution(a) {
let len = a.length;
let left = Array(len);
let right = Array(len);
left[0] = a[0];
for (let i = 1; i < len; i++) {
left[i] = Math.min(left[i - 1], a[i]);
}
right[len - 1] = a[len - 1];
for (let i = len - 2; i >= 0; i--) {
right[i] = Math.min(right[i + 1], a[i]);
}
return new Set([...left, ...right]).size;
}
left 배열 계산에 , right 배열 계산에 ,Set 생성에 의 시간 복잡도를 가지므로 최종적으로 의 시간 복잡도를 가져 문제 없이 통과할 수 있게 됩니다.
