
이 문제는 스택의 기본 원리는 이용한 문제이다.
문제 이해
[ 스택 이해 ]
스택 이해는 아래의 링크를 타고 다른 스택 문제 해결과정을 통해 이해하길 바란다.
https://velog.io/@nyezxxj/Java-%EB%B0%B1%EC%A4%80-28278-%EC%8A%A4%ED%83%9D-2
이 문제의 내용은 다음과 같다.
간식을 받으려 번호표를 받고 대기하는 사람들이 있다.
뒤죽박죽 섞여있는 사람들은 번호표 순서대로 줄 세우기 위해 스택 2개를 통해 줄을 바로 세운다.
순서대로 받을 수 있다면 "Nice"를, 순서대로 받을 수 없다면 "Sad"를 출력하면 된다.


주의 사항
[ 현재 줄 서있는 곳 ]은 스택 1, [ 한 명씩만 설 수 있는 공간 ]을 스택2 라고 할 때,
스택 2 -> 스택 1 의 이동은 불가능하다.
스택 여러개를 응용한 문제로, 아래의 단계별로 이해하면 도움이 될 것이다.


예제 입력을 바탕으로 설명하자면
코드 이해
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
import java.util.StringTokenizer;
public class Main {
static Stack<Integer> line = new Stack<>();
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int n = Integer.parseInt(br.readLine());
int[] array = new int[n];
st = new StringTokenizer(br.readLine());
// 배열에 받고 스택에 순서대로 넣는 과정
for (int i = 0; i < n; i++) {
array[i] = Integer.parseInt(st.nextToken());
}
for (int i = n - 1; i >= 0; i--) {
line.push(array[i]);
}
System.out.println(solve(n));
}
public static String solve(int n) {
Stack<Integer> stack = new Stack<>();
Stack<Integer> check = new Stack<>();
String str = "Nice";
for (int i = 1; i <= n; i++) {
int x = 0, y = 0;
while (true) {
if (!line.empty()) x = line.peek();
if (!stack.empty()) y = stack.peek();
if (i == y) {
check.push(stack.pop());
break;
}
if (i == x) {
check.push(line.pop());
break;
}
if (i < x) stack.push(line.pop());
if ((line.empty() && !stack.empty()) && (i != y)) {
str = "Sad";
return str;
}
}
}
int x = check.pop();
int y;
for (int i = 1; i < n; i++) {
y = check.pop();
if (y > x) {
str = "Sad";
break;
}
x = y;
}
return str;
}
}
코드를 크게 main 부분과 핵심 해결메소드(solve)로 나누었다.
5
5 4 1 3 2
n = 5
array = 2 3 1 4 5
line = 5 4 1 3 2
main에서 line을 순서대로 넣는 것 까지 끝내고 solve 메소드 실행
1-1. i = 1
1-2. line에 값이 있다면 ? x = 5
1-3. stack에 값이 있다면 ? y= 0
1-4. i인 1보다 5가 더 큼 = stack에 5 push
2-1. i = 1
2-2. line에 값이 있다면? x = 4
2-3. stack에 값이 있다면? y = 5
2-4. i인 1보다 5가 더 큼 -> 4도 더 큼 = stack에 4 push
3-1. i = 1
3-2. line 값 x = 1
3-3. stack 값 y = 4
3-4. i인 1과 y는 다름 / x는 같음 = line.pop() + break;
4-1. i = 2
4-2. line 값 x = 3
4-3. stack 값 y = 4
4-4. i인 2보다 y가 더 큼 -> x도 더 큼 = stak에 3 push
5-1. i = 2
5-2. line 값 x = 2
5-3. stack 값 y = 3
5-4. i인 2와 y는 다름 / x는 같음 = line.pop() + break;
6-1. i = 3
6-2. line 값 x = 없음
6-3. stack 값 y = 3
6-4. i인 3과 y가 같음 = stack.pop + break;
의 과정으로 4와 5까지 모두 끝난 후 "Nice"를 반환한다.
[ 1 ]
만약 예제처럼 딱 맞는 값이 아니라 ex) 45312 가 들어왔다면
stack : 4 5
check : 1 2 3
의 상태에서 stack의 5가 무한반복을 자아낸다.
-> 이 경우의 예외처리로 만약 line은 모두 빼내고 && stack은 아직 남아있는 상태에서 비교하려는 순서(i)와 스택의 값(y)가 같지 않다면 "Sad"를 반환하도록 했다.
[ 2 ]
모두 잘 끝났다면 check를 한번 더 점검한다.
check : 1 2 3 4 5 순으로 들어가있을 경우 5부터 숫자가 빠지기 때문에(선입후출) for문을 통해 뒤에서부터 꺼내 비교해주어야 한다.
for문을 돌리기 전 값 하나를 미리 빼준 후 x에 넣어준다.
그리고 for문에서 y에 값을 하나 넣은 후 x > y가 성립하는지 확인한다.
만약 성립되지 않는다면 "Sad"를 반환하도록 한다.
+) 성립했다면 다음 단계에서 x = y로 대입하고 y는 다시 앞의 값을 꺼내서 비교하도록 한다.
한줄평
최적화보다는 문제를 푸는데에 집중해서 생각보다 코드가 길었다.
단계별로 코드를 바로 풀어내기 어렵다면 필기를 통해 단계를 정리한 후 코드로 구현해 보는 것을 추천한다.