[백준 3425] 고스택 (Java, 시뮬레이션)
Algorithm/백준(BOJ)

[백준 3425] 고스택 (Java, 시뮬레이션)

반응형

[백준 3425] 고스택 (Java, 시뮬레이션)


 

 

B형 역량테스트를 보기 하루 전이다.

인터넷 상에 추천문제로 나온 고스택 문제를 풀었다. 시뮬레이션이라 문제푸는 감을 익히기에 좋을 것 같다.

 

문제 : 출처

 

3425번: 고스택

문제 고창영은 스택을 조금 변형해서 고스택을 만들었다. 고스택은 숫자만을 저장할 수 있고, 다음과 같은 10가지 연산을 수행할 수 있다. 편의상 스택의 가장 위에 저장된 수를 첫 번째 수라고 하고, 그 다음은 차례대로 두 번째 수, 세 번째 수라고 한다. NUM X: X를 스택의 가장 위에 저장한다. (0 ≤ X ≤ 109) POP: 스택 가장 위의 숫자를 제거한다. INV: 첫 번째 수의 부호를 바꾼다. (42 -> -42) DUP: 첫 번째 숫자를 하

www.acmicpc.net

 

우선 문제에서 사용해야 하는 스택 구현에는 삽입, 삭제가 많기 때문에 LinkedList를 활용해야 시간을 줄일 수 있다.

 

또한 실제 역량테스트에서는 라이브러리 구현이 불가능하기 때문에, 직접 LinkedList를 클래스로 구현해서 사용했다.

 

문제 자체에 ERROR로 표시해야 하는 조건이 상당히 많은데 중간중간 낚시 요소가 많으므로 주의해야한다.

 

그냥 주어진 테스트케이스로는 보지 못할 예외 케이스가 많기 때문에, 스스로 수많은 테스트 과정을 거쳐봐야 한다.

일단 10^9를 초과하면 안되니, 타입을 int형으로는 불가능하다는 등등.. 이런 부분에서 실수하지 않도록 예외사항을 잘 체크하자.

 

 

정답이 잘 나왔지만, 공백이 나올 때마다 초기화 과정을 거치면서 메모리초과 문제가 가장 컸다.

 

따라서 10만개 크기의 배열을 이때마다 초기화를 시켜주는 건 상당히 낭비였고, index의 개수를 저장해두고 그만큼만 덮어서 활용하는 방식으로 접근해서 해결할 수 있었다.

 

 

실제 레퍼런스 코드는 시험 자체에서 제공되기 때문에, LinkedList를 외우는 것보다 이해하고 사용할 수 있어야 한다.

 

 

전체 소스코드

 

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
import java.io.BufferedReader;
import java.io.InputStreamReader;
 
class ListNode {
    long data;
    ListNode prev;
    ListNode next;
     
    public ListNode()
    {
        data = 0;
        prev = this;
        next = this;
    }
 
    public static ListNode appendListNode(ListNode head, long data)
    {
        ListNode node = new ListNode();
        node.data = data;
        if (head == null)
        {
            head = node;
        }
        else
        {
            ListNode last = head.prev;
            last.next = node;
            head.prev = node;
            node.prev = last;
            node.next = head;
        }
        return head;
    }
     
    public static ListNode removeListNode(ListNode head, ListNode node)
    {
        if (head == head.next)
        {
            return null;
        }
        else
        {
            ListNode prevNode = node.prev;
            ListNode nextNode = node.next;
            prevNode.next = nextNode;
            nextNode.prev = prevNode;
            return (head == node) ? nextNode : head;
        }
         
    }
}
 
public class Main3425 {
    
    static String[] cal = new String[100001];
    static long[] add = new long[100001];
    static int idx, numidx;
    static int a, b;
    
    static long error = Long.MAX_VALUE;
    
    public static void main(String[] args) throws Exception {
 
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        //END를 받을 때까지 프로그램 수행 연산을 받는다.
        //개수를 알지 못하기 때문에, ArrayList에 저장?
        
        //NUM은 공백으로 숫자가 하나 들어온다
        
        //END 이후에는 N값과 N개의 수가 들어옴
        
        //빈칸이 들어오면 ArrayList 비워주기
        
        //QUIT이 들어오면 프로그램 종료
        
        idx = 0;
        numidx = 0;
        a = b = 0;
        
        while(true) {
            
            String[] input = br.readLine().split(" ");
            //종료조건
            if(input[0].equals("QUIT")) {
                break;
            }
            
            
            if(input[0].equals("END")) { // 하나의 프로그램 끝남 - N값 받고 실행
                int N = Integer.parseInt(br.readLine());
                
                for (int i = 0; i < N; i++) {
                    long res = solution(Long.parseLong(br.readLine()));
                    
                    if(res == error)
                        System.out.println("ERROR");
                    else
                        System.out.println(res);
                }
                
            }
            else if(input[0].equals("")) { // 공백일 때 ( 초기화 )
                idx = numidx = 0;
                System.out.println(); // 출력 시 띄어쓰기
            }
            else {
                cal[idx++= input[0];
                a = idx;
                
                if(input[0].equals("NUM")) {
                    add[numidx++= Integer.parseInt(input[1]);
                    b = numidx;
                }
            }
            
        }
    }
    
    public static long solution(long num) {
        //cal 배열에 연산 프로그램이 들어가있는 상태
        //해당 num을 가지고 스택연산 실행해야 함 (연결리스트 활용)
        ListNode head = null;
        head = ListNode.appendListNode(head, num);
        
        idx = numidx = 0;
        while(idx < a && numidx <= b) {
            
            if(cal[idx].equals("NUM")) { // 스택 가장 위 저장
                long number = add[numidx++];
                head = ListNode.appendListNode(head, number);
                
            } else if(cal[idx].equals("POP")) { // 가장 위 숫자 제거
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev);
                else
                    return error;
                    
            } else if(cal[idx].equals("INV")) { // 첫번째 수 부호 바꿈
                long number = head.prev.data;
                head.prev.data = -number;
                
            } else if(cal[idx].equals("DUP")) { // 첫번째 숫자 하나 더 가장 위에 저장
                long number = head.prev.data;
                ListNode.appendListNode(head, number);
                
            } else if(cal[idx].equals("SWP")) { // 첫번째와 두번재 숫자 바꿈
                
                long top = head.prev.data; // 맨위 숫자
                long second = head.prev.prev.data;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //맨위 숫자 제거
                else
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //다음 숫자 제거
                else
                    return error;
                
                head = ListNode.appendListNode(head, top);
                head = ListNode.appendListNode(head, second);
                
            } else if(cal[idx].equals("ADD")) { // 첫번째 두번재 숫자 하나로 더함
                long top = head.prev.data; // 맨위 숫자
                long second = head.prev.prev.data;
                long sum = top + second;
                
                if(sum > 1000000000 || sum < -1000000000)
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //맨위 숫자 제거
                else
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //다음 숫자 제거
                else
                    return error;
                
                head = ListNode.appendListNode(head, sum);
                
            } else if(cal[idx].equals("SUB")) { // 두번째 숫자 - 첫번째 숫자
                long top = head.prev.data; // 맨위 숫자
                long second = head.prev.prev.data;
                long sum = second - top;
                
                if(sum > 1000000000 || sum < -1000000000)
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //맨위 숫자 제거
                else
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //다음 숫자 제거
                else
                    return error;
                
                head = ListNode.appendListNode(head, sum);
            } else if(cal[idx].equals("MUL")) { // 첫번째 두번재 숫자 하나로 곱합
                long top = head.prev.data; // 맨위 숫자
                long second = head.prev.prev.data;
                long sum = top * second;
                
                if(sum > 1000000000 || sum < -1000000000)
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //맨위 숫자 제거
                else
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //다음 숫자 제거
                else
                    return error;
                
                head = ListNode.appendListNode(head, sum);
            } else if(cal[idx].equals("DIV")) { // 첫번째 두번재 숫자 나눈 몫 저장
                
                long top = head.prev.data; // 맨위 숫자
                if(top == 0return error; // 0으로 나눴을 때
                long second = head.prev.prev.data;
                long sum = Math.abs(second) / Math.abs(top);
                
                //음수 체크
                int minusCnt = 0;
                if(top < 0) minusCnt++;
                if(second < 0) minusCnt++;
                
                if(minusCnt == 1) {
                    sum = -sum;
                }
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //맨위 숫자 제거
                else
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //다음 숫자 제거
                else
                    return error;
                
                head = ListNode.appendListNode(head, sum);
                
            } else if(cal[idx].equals("MOD")) { // 나누고 나머지 저장
                
                long top = head.prev.data; // 맨위 숫자
                if(top == 0return error; // 0으로 나눴을 때
                long second = head.prev.prev.data;
                long sum = Math.abs(second) % Math.abs(top);
                
                if(second < 0) {
                    sum = -sum;
                }
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //맨위 숫자 제거
                else
                    return error;
                
                if(head != null)
                    head = ListNode.removeListNode(head, head.prev); //다음 숫자 제거
                else
                    return error;
                
                head = ListNode.appendListNode(head, sum);
                
            } 
            
                
            idx++;
        }
        
        
        int count = 0;
        long data = 0;
        
        while(head != null) {
            data = head.data;
            head = ListNode.removeListNode(head, head.prev);
            count++;
        }
        
        if(count == 1) {
            return data;
        }
        else {
            return error;
        }
    }
 
}
 
cs

 

 

 

 

 

 

반응형