[백준] 1874번 C/C++ 풀이 _ 스택 수열



시간 제한메모리 제한제출정답맞은 사람정답 비율
2 초128 MB122692873218525.505%

문제

스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 먼저 들어간 자료가 제일 나중에 나오는 (FILO, first in last out) 특성을 가지고 있다.

1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이 때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.

입력

첫 줄에 n(1≤n≤100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.

출력

입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.

예제 입력 

8
4
3
6
8
7
5
2
1

예제 출력 

+
+
+
+
-
-
+
+
-
+
+
-
-
-
-
-

힌트

1부터 n까지에 수에 대해 차례로 [push, push, push, push, pop, pop, push, push, pop, push, push, pop, pop, pop, pop, pop] 연산을 수행하면 수열 [4, 3, 6, 8, 7, 5, 2, 1]을 얻을 수 있다.

출처

알고리즘 분류

>> 문제 해결 과정
시간 초과 문제 발생으로 알고리즘에 이상이 있나 싶었다. 
아무리 살펴봐도 다른 알고리즘과 비교해봤을 때, 복잡도에서 큰 차이를 느끼지 못했는데 질의응답을 살펴보다가 단서를 얻었다.

'endl' 을 사용하면 버퍼를 비우기 때문에 매우 느리다. 
'\n' 을 사용해야 한다. 

72줄의 endl 을 \n 로 변경하니 아주 잘 되었다. 

>> 정답

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <queue>
#include <stack> 
#include <vector>
 
using namespace std;    
 
int total_num; 
vector<int> remain_num_vec;
int remain_num_vec_index = 0 ; 
vector<char> answer_char_queue; 
queue<int> want_print;
stack<int> find_stack;
 
int main() {
    cin >> total_num;
 
    // 원하는 출력을 vector 에 넣기
    for (int i = 0; i < total_num; i++) {
        int sub;
        cin >> sub;
        want_print.push(sub);
    }
 
    //  vec 에 숫자 순서대로 넣기 
    for (int i = 0; i < total_num; i++) {
        remain_num_vec.push_back(i+1);
    }
 
    // 처음에 주어진 숫자로 stack 채우기
    for (int i = 0; i < want_print.front(); i++) {
        find_stack.push(remain_num_vec[remain_num_vec_index++]);
        answer_char_queue.push_back('+');
    }
    want_print.pop();
 
    // 처음에 주어진 숫자를 stack 에서 빼기 
    find_stack.pop();
    answer_char_queue.push_back('-');
 
    while (want_print.size()) {
        // 출력하고자 하는  놈을 빼봅니다. 
        int this_print = want_print.front();
                
        // 만약 stack 이 비어있다면 채워준다. 
        if (find_stack.size() == 0 ) {
            find_stack.push(remain_num_vec[remain_num_vec_index++]);
            answer_char_queue.push_back('+');
        }
        // 만약 출력하고자 하는 놈이 스택에 있는 놈보다 작으면 
        else if (this_print < find_stack.top()) {
            cout << "NO";
            return 0
        }
        // 같으면
        else if (this_print == find_stack.top()) {
            // 주어진 숫자를 stack 에서 빼기 
            find_stack.pop();
            answer_char_queue.push_back('-');
            want_print.pop();
        }
        // 크면 
        else { 
            find_stack.push(remain_num_vec[remain_num_vec_index++]);
            answer_char_queue.push_back('+');
        }  
    }
 
    int total_size = answer_char_queue.size();
    
    for (int i = 0; i < total_size; i++){
        cout << answer_char_queue[i] << "\n";
    }
 
    return 0
}
cs