[백준] 스택수열
스택
그리디
백준
easy
문제
1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.
입력
첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.
8
4
3
6
8
7
5
2
1
출력
입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.
+
+
+
+
-
-
+
+
-
+
+
-
-
-
-
-
첫번째 접근법
Sorting 후, 재귀 호출
일단, 문제가 이해가 안갔다. 스택
을 이용해서, 입력받은 순서
대로 수열
을 스택에 쌓인 값으로 만들 수 있냐는 문제인데 스택에 push 하는 것은 오름차순을 지켜야 한단다. 뭔말인가 했다. :sweat_smile:
4 3 6 8 7 5 2 1
위와 같이 값이 주어지면, 스택에는 오름차순으로만 넣을 수 있고, 이 스택을 push, pop 하는 과정을 통해 위의 수열을 똑같이 만들 수 있냐는 문제이다.
문제를 이해하고 아래와 같이 풀면 된다고 생각했다.
- 입력받은 숫자를 오름차순 sorting
- sorting 된 리스트를 순서대로
push
- push 할 때 마다, pop할 수 있는 수 인지 확인
- YES : 1) pop 2) find[] = True
- check_seq(indx + 1) 재귀 호출 (남아 있는 스택에서 pop 할 수 있는 값이 있는지 확인)
- NO : 아무것도 하지 않고 return index
- YES : 1) pop 2) find[] = True
- 모든 배열 list를 다 순환했을 때 check한 index값이 수열의 size와 동일하다면, 수열을 모두 pop한 뜻이므로 YES
- 아니라면 NO 출력
# 파이썬 재귀 최대 1000
import sys
sys.setrecursionlimit(100000)
n = int(input())
find = [False for i in range(200000)]
stack = list()
idx = 0
seq = list()
answer = list()
def solve():
for i in range(n):
seq.append(int(input()))
global idx
data = seq[:] # 복사
data.sort()
for i in range(n):
if not find[data[i]]:
stack.append(data[i])
answer.append("+")
idx = check_seq(idx)
if n == idx:
for i in range(len(answer)):
print(answer[i])
else:
print("NO")
def check_seq(index):
if len(stack) < 1:
return index
chk_value = stack[-1]
if chk_value == seq[index]:
pop_value = stack.pop()
answer.append("-")
find[pop_value] = True
return check_seq(index + 1)
return index
What was the problem?
-
런타임 에러 파이썬에서는 1,000개 이상의 재귀는 기본적으로 제한하고 있다.
python has a recurison depth of < 1000~. so for the purpose of this assignment I'm increasing it따라서, 아래 코드를 최상단에 추가해줘야 한다.
import sys sys.setrecursionlimit(100000)
-
경우의 수 배열 size 초과
입력 제한은 1 ≤ n ≤ 100,000 이라 처음에 find[] 배열을
find = [False for i in range(100000)]
0부터 10,000 공간을 만들었다. But n은 1부터 10,000까지 입력되는 것이므로 나의 배열은 999999 까지 밖에 못받아서런타임에러
가 났던 것이다.find = [False for i in range(1, 100001)]
이렇게 바꿔줘야 한다.런타임 에러가 날 경우
입력제한에 따른 배열 size를 잘 살펴보자
최소, 최대 입력을 잘 살펴보자.
강의 해법
Greedy Algorithm
강의해법은 입력 받을 때마다 바로 최적의 해를 찾는 Greedy 기법을 사용했다.
사실, 입력받은 숫자 기준으로 하위 숫자를 바로 Stack에 쌓는 아이디어는 정말 떠오르지 않았다.
- 입력받을 때마다 해당 숫자 아래 숫자를 모두 스택에 쌓는다 (이렇게하면 무조건 오름차순으로 쌓아지니까)
- pop했는데, 값이 지금 데이터가 아니면 불가능한 경우이므로 종료한다.
Conclusion
강의해법과 내 해법을 비교해봤다.
구분 | 메모리 | 시간 |
---|---|---|
내 해법 | 51416KB | 4212ms |
강의 해법 | 31712KB | 4688ms |
- 재귀를 사용했으므로, 메모리가 내 해법이 더 크게 나왔다.
- 하지만 시간적 측면에선 아주 근소하게 더 좋은(?) 것 같다.
- 사실 나의 해법은
sorting
까지 들어갔고, 수열을 만들 수 없는 NO case일 경우에도 모든 입력 숫자를for
반복이 끝나야지 이게 NO인지 알 수 있는 반면에 강의해법은 입력받을 때마다 체크를 해서, pop 했을 때 자신의 숫자가 아니라면 바로exit(0)
을 하므로 더 효율적일 것 이라고 생각이 든다.