백준 17298 오큰수 파이썬 풀이
문제
크기가 N인 수열 A = A1, A2, ..., AN이 있다. 수열의 각 원소 Ai에 대해서 오큰수 NGE(i)를 구하려고 한다. Ai의 오큰수는 오른쪽에 있으면서 Ai보다 큰 수 중에서 가장 왼쪽에 있는 수를 의미한다. 그러한 수가 없는 경우에 오큰수는 -1이다.
예를 들어, A = [3, 5, 2, 7]인 경우 NGE(1) = 5, NGE(2) = 7, NGE(3) = 7, NGE(4) = -1이다. A = [9, 5, 4, 8]인 경우에는 NGE(1) = -1, NGE(2) = 8, NGE(3) = 8, NGE(4) = -1이다.
정답코드
#오큰수
N = int(input())
arr = list(map(int,input().split()))
result = [-1] * N
stack = [0]
for i in range(1,N):
while stack and arr[stack[-1]] < arr[i]:
result[stack.pop()] = arr[i]
stack.append(i)
print(*result)
시간복잡도 O(N^2) 였던 for 문 X 2 와 달리, for 문안에 스택이 들어있는 것은 시간복잡도가 O(N)이다.
코드 진행 순서
입력 예시 5, 3 8 2 7 4
핵심코드
for i in range(1,N):
while stack and arr[stack[-1]] < arr[i]:
result[stack.pop()] = arr[i]
stack.append(i)
while stack 이라는 조건과 조건을 만족할 경우 stack.pop()을 통해 조건을 만족하는 경우 stack이 줄도록 설계되어 있다.
Q)스택이 쌓이면서 왼쪽에서 오른쪽 인덱스로 체크하는 게 아니라, 오른쪽 인덱스에서 왼쪽으로 반대로 체크하게 됩니다.(후입선출 구조)
그렇다면 예를들어, while 문의 조건을 stack[-1]이 만족한다고 할 때, 조건문이 한바퀴 돌고도 조건을 만족한다고 가정한 경우, 그 때 answer[stack[-2]] = arr[i]를 넣을 수 있다고 확신할 수 있나요??
-> 네
왜냐하면 stack이 쌓였다는 뜻은 arr[stack[-1] < arr[i] 비교 조건에 의해 arr의 직전 index 보다 값이 더 작다는 것을 의미합니다. 따라서 비교를 해야되고 그래서 while문이 한번 더 돌게 설계가 된 것입니다. 이떄 그 while 문에서의 조건 또한 만족한다면, 오른쪽에서 큰 수 중 가장 왼쪽에 있는 수가 되는 것이므로 확신 할 수 있습니다.
예시(7 5 8 1) 인 경우 answer = [8 8 -1 -1]
Q) 이 문제가 어려운 이유와 스택을 활용할 수 있는 이유??
-> 이문제가 어려운 이유는 단순한듯 보이지만, 시간 복잡도 와 자료구조를 활용해야하는 문제이기 때문이다.
forX2번으로 시간복잡도O(N^2)이 되는 풀이를 스택 자료구조를 활용해 시간복잡도 O(N)으로 줄여 문제를 해결해야 한다. 아울러 스택에 적응하지 못한 사람의 경우 이 문제에 스택을 어떻게 적용해야할지 감을 잡기 무척이나 어렵다. ( 나의 경우)
그렇다면 스택 자료구조를 사용할 수 있는 이유는 무엇인가?
1.왼쪽에서 오른쪽 혹은 오른쪽에서 왼쪽으로 순차적으로 방향성을 갖고 있다.
2. 조건을 만족하지 않으면 "저장"되었다가 나중에라도 체크해야한다.
-> 스택의 구조는 "쌓인다"라는 특징을 가진다.
풀이과정
시간초과 코드
#오큰수
N = int(input())
answer = []
su_yeol = list(map(int,input().split()))
for i in range(len(su_yeol)):
flag = 0
for j in range(len(su_yeol)):
#중복제거
if(i<j):
if(su_yeol[i] < su_yeol[j]):
answer.append(su_yeol[j])
flag = 1
break
elif(j == len(su_yeol) - 1 and flag == 0):
answer.append(-1)
answer.append(-1)
for i in answer:
print(i,end=" ")
for 문을 2번사용하였는데, 이 때문에 시간초과가 났다.
for 문 한번에 시간복잡도는 O(N) 인데, for 문을 두번 연속 사용하였으니 시간복잡도가 O(N^2)인 코드이다. 따라서 이러한 문제 때문에 시간초과가 난 것이다.
정답코드를 참고했음에도 불구하고, stack을 활용하는 이유가 무엇인지 헷갈렸고, while 문과 stack을 활용한 설계가 익숙지 않아 , 꽤 많은 시간 고민을 하였다.
배운점 && 공부방향
1. 자료구조를 사용해 시간복잡도를 최소화 하자.
->for 문 X 2 , for 문 X stack 의 시간복잡도 비교
2. Stack은 어떤 문제 유형에서 활용할 수 있는가? 에 대해 적응할 필요가 있다.
-> 문제를 풀면서 처음에 stack을 쓸 수 있을지 생각 자체가 나지 않았음.
3. 조건을 만족하지 않는 경우를 default 값으로 하는 풀이
result = [-1] * N
'CS > 알고리즘' 카테고리의 다른 글
알고리즘 구현 실수 유형 정리 (0) | 2022.04.15 |
---|---|
백준 11401번 이항계수3 파이썬 풀이 (0) | 2022.04.12 |
백준 4949 균형 잡힌 세상 파이썬 풀이 (0) | 2022.04.05 |
백준 1707번 이분 그래프 파이썬 풀이 (0) | 2022.04.04 |
백준 7562 나이트의 이동 파이썬 풀이 (0) | 2022.04.02 |