홍준이는 요즘 주식에 빠져있다. 그는 미래를 내다보는 눈이 뛰어나, 날 별로 주가를 예상하고 언제나 그게 맞아떨어진다. 매일 그는 아래 세 가지 중 한 행동을 한다.
- 주식 하나를 산다.
- 원하는 만큼 가지고 있는 주식을 판다.
- 아무것도 안한다.
홍준이는 미래를 예상하는 뛰어난 안목을 가졌지만, 어떻게 해야 자신이 최대 이익을 얻을 수 있는지 모른다. 따라서 당신에게 날 별로 주식의 가격을 알려주었을 때, 최대 이익이 얼마나 되는지 계산을 해달라고 부탁했다.
예를 들어 날 수가 3일이고 날 별로 주가가 10, 7, 6일 때, 주가가 계속 감소하므로 최대 이익은 0이 된다. 그러나 만약 날 별로 주가가 3, 5, 9일 때는 처음 두 날에 주식을 하나씩 사고, 마지막날 다 팔아 버리면 이익이 10이 된다.
입력의 첫 줄에는 테스트케이스 수를 나타내는 자연수 T가 주어진다. 각 테스트케이스 별로 첫 줄에는 날의 수를 나타내는 자연수 N(2 ≤ N ≤ 1,000,000)이 주어지고, 둘째 줄에는 날 별 주가를 나타내는 N개의 자연수들이 공백으로 구분되어 순서대로 주어진다. 날 별 주가는 10,000이하다.
각 테스트케이스 별로 최대 이익을 나타내는 정수 하나를 출력한다. 답은 부호있는 64bit 정수형으로 표현 가능하다.
<입력>
3
3
10 7 6
3
3 5 9
5
1 1 3 1 2
<출력>
0
10
5
이 문제는 그리디 알고리즘을 이용해 푸는 문제이다. 직접 구현한 코드로는 시간 초과로 문제를 해결하지 못해 다른 사람들이 구현한 코드를 보고 비교해보았다. 내가 생각한 아이디어는 아래와 같다.
- 가장 큰 주가와 작은 주가를 구한다.
- 뽑아낸 원소가 가장 작은 주가와 같다면 benefit 배열에 넣는다.
- 뽑아낸 원소가 가장 큰 주가와 같다면 benefit 배열에 있는 원소들을 판 값을 구한다.
from collections import deque
T = int(input())
for _ in range(T):
N = int(input())
stock = deque(list(map(int, input().split())))
benefit = []
stock_min = min(stock)
stock_max = max(stock)
total = 0
while len(stock) > 0:
tmp = stock.popleft()
if tmp == stock_min and len(stock) > 0:
benefit.append(tmp)
elif tmp == stock_max and len(benefit) > 0:
while len(benefit) > 0:
total += (tmp-benefit.pop())
if len(stock) > 0:
stock_min = min(stock)
stock_max = max(stock)
print(total)
내가 구현한 코드의 문제는 높은 주가를 계속 갱신하는 곳에서 문제가 생기는 것 같았다. 그래서 이 곳의 코드를 참고해 다시 구현했다. 내 코드와의 다른 점은 원소를 뒤에서부터 비교하는 것 이었다. 뒤에서부터 비교하면 싼 가격이면 바로 팔고 비싸면 그것을 기준으로 다시 반복하면 되기 때문이다.
T = int(input())
for _ in range(T):
N = int(input())
stock = list(map(int, input().split()))
total = 0
while len(stock) > 0:
tmp = stock.pop()
for i in range(len(stock)-1, -1, -1):
if tmp >= stock[i]:
total += (tmp-stock[i])
stock.pop()
else:
break
print(total)
앞에서부터 원소를 꺼내서 비교하는 것이 훨씬 복잡하고 구현하기 어렵다는 것을 알았다. 나와 다르게 구현한 코드를 보고 비교하니 내가 부족한 점이 무엇인지 잘 알 수 있었다.ㅎㅎ