일렬로 나열된 n개의 풍선이 있습니다. 모든 풍선에는 서로 다른 숫자가 써져 있습니다. 당신은 다음 과정을 반복하면서 풍선들을 단 1개만 남을 때까지 계속 터트리려고 합니다.
여기서 조건이 있습니다. 인접한 두 풍선 중에서 번호가 더 작은 풍선을 터트리는 행위는 최대 1번만 할 수 있습니다. 즉, 어떤 시점에서 인접한 두 풍선 중 번호가 더 작은 풍선을 터트렸다면, 그 이후에는 인접한 두 풍선을 고른 뒤 번호가 더 큰 풍선만을 터트릴 수 있습니다.
당신은 어떤 풍선이 최후까지 남을 수 있는지 알아보고 싶습니다. 위에 서술된 조건대로 풍선을 터트리다 보면, 어떤 풍선은 최후까지 남을 수도 있지만, 어떤 풍선은 무슨 수를 쓰더라도 마지막까지 남기는 것이 불가능할 수도 있습니다.
일렬로 나열된 풍선들의 번호가 담긴 배열 a가 주어집니다. 위에 서술된 규칙대로 풍선들을 1개만 남을 때까지 터트렸을 때 최후까지 남기는 것이 가능한 풍선들의 개수를 return 하도록 solution 함수를 완성해주세요.
- a의 길이는 1 이상 1,000,000 이하입니다.
- a[i]는 i+1 번째 풍선에 써진 숫자를 의미합니다.
- a의 모든 수는 -1,000,000,000 이상 1,000,000,000 이하인 정수입니다.
- a의 모든 수는 서로 다릅니다.
a | result |
---|---|
[9,-1,-5] | 3 |
[-16, 27, 65, -2, 58, -92, -71, -68, -61, -33] | 6 |
만약, 번호가 더 작은 풍선을 터트릴 수 없었다면,
마지막에 남는 풍선은 항상 최소값을 가지는 풍선일것이다.
하지만 해당 조건으로 최소값을 갖지 않는 풍선도 마지막에 남을 수 있게 된다.
전체 풍선 중 가장 작은 값을 갖는 풍선을 m,
최소값 이상의 값을 갖는 풍선을 k라고 할 때,
풍선 k가 마지막에 남기 위해서는 최후 2개의 풍선은 m과 k이어야 하며,
이때까지 "인접한 풍선 중 번호가 더 작은 풍선을 터트리는" 작업을
단 한번도 하지 않아야 한다.
(즉, 이전까지는 항상 더 큰 값을 갖는 풍선을 터트려야 한다)
풍선의 값이 담긴 배열을 순회하며,
현재 풍선을 중심으로 왼쪽, 오른쪽 배열에서의 최소값을 구하고
왼쪽 배열에서의 최소값과 오른쪽 배열에서의 최소값 중
하나라도 현재 풍선의 값보다 크다면
현재 풍선은 마지막에 남아있을 수 있는 풍선이다.
풍선의 값이 담긴 배열을 순회하며,
현재 풍선을 중심으로 좌, 우 배열에서 큰 값을 갖는 풍선을 터트리는 작업을 반복하면
결국 각 배열에서 남는 풍선은 각 배열에서 최소값을 가지는 풍선이며,
작은 값을 갖는 풍선을 2번 터트릴수는 없기 때문에
두 배열의 최소값이 모두 현재 풍선의 값보다 작다면
현재 풍선은 마지막에 남을 수 없는 풍선이다.
하지만 왼쪽 배열에서의 최소값과 오른쪽 배열에서의 최소값 중
하나라도 현재 풍선의 값보다 크다면,
작은 값을 갖는 풍선을 최대 1번 터트린다는 조건을 만족시키면서
현재 풍선을 마지막에 남길 수 있다.
def solution(a):
answer = 0
arr = sorted(a, reverse=True)
used = set()
left_min = a[0]
right_min = arr[-1]
for i in range(len(a)):
used.add(a[i])
if left_min >= a[i] or right_min >= a[i]:
answer += 1
left_min = min(left_min, a[i])
while len(arr) > 0 and arr[-1] in used:
arr.pop()
if len(arr) > 0: right_min = arr[-1]
return answer
전체 배열의 최소값은 유일하게 존재하고,
현재 풍선이 최소값을 갖는 풍선 일 때를 제외하고는,
모든 풍선의 왼쪽 또는 오른쪽에는 최소값을 가지는 풍선이 존재한다.
따라서, 위의 좌, 우로 나누어 생각하는 접근 방식을
"지금까지 순회한 원소 중 현재 풍선의 값이 가장 작은지" 만을 판단하는것으로
생각할 수 있다.
그 이유는, 순회가 최소값의 방향으로 진행 될 때
최소값을 갖는 풍선 딱 하나를 제외하고는
좌, 우 중 한쪽 배열의 최소값은 항상 현재 풍선의 값보다 작을것이기 때문이다.
따라서, 다음과 같은 풀이가 가능하다.
전체 최소값을 구한뒤,
배열을 2번 순회한다.
한번은 정방향으로, 다른 한번은 역방향으로.
두 순회 모두 최소값에 다다를 때 종료된다.
각 순회에 대한 최소값을 별도로 갱신하며,
만약 현재 풍선의 값이 현재 순회의 최소값 보다 작다면
그 풍선은 자신을 기준으로,
"최소값이 포함되지 않은 배열에서 가장 작은 값을 갖는 풍선보다 값이 작은 풍선" 이므로
"인접한 두 풍선중 값이 큰 풍선"만 터트리면서
"최소값을 갖는 풍선과 단 둘이 남는 풍선"이 될 수 있다.
def solution(a):
answer = 1
M = min(a)
for _ in range(2):
m = a[0]
i = 1
while m != M:
if m >= a[i]:
m = a[i]
answer += 1
i += 1
a.reverse()
return answer