스택
0.5 초 (추가 시간 없음) | 256 MB | 295270 | 111241 | 80509 | 38.396% |
문제
정수를 저장하는 스택을 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.
명령은 총 다섯 가지이다.
- push X: 정수 X를 스택에 넣는 연산이다.
- pop: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.
- size: 스택에 들어있는 정수의 개수를 출력한다.
- empty: 스택이 비어있으면 1, 아니면 0을 출력한다.
- top: 스택의 가장 위에 있는 정수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.
입력
첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.
출력
출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.
예제 입력 1 복사
14
push 1
push 2
top
size
empty
pop
pop
pop
size
empty
pop
push 3
empty
top
예제 출력 1 복사
2
2
0
2
1
-1
0
1
-1
0
3
예제 입력 2 복사
7
pop
top
push 123
top
pop
top
pop
예제 출력 2 복사
-1
-1
123
123
-1
-1
이 문제를 제일 먼저 풀기로 한 건..
스택밖에 기억이 잘 안 나서이다.
알고리즘 공부 좀 다시 열심히 해야지 정말루~
++ 이따 스택 찾아보고 내용 추가할 것.
문제 발생.
입력부터가 난관이다..
push X 이거 어떻게 넣는데...
일단 switch문으로 짜봤다.
package Week02.BJ_10828;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Stack<Integer> stack = new Stack<>();
int N = Integer.parseInt(br.readLine());
for (int i = 0; i < N; i++) {
String input = br.readLine();
switch (input) {
case "pop":
if (!stack.isEmpty()) {
System.out.println(-1);
}
System.out.println(stack.pop());
break;
case "size":
System.out.println(stack.size());
break;
case "empty":
if (stack.isEmpty()) {
System.out.println(1);
break;
}
System.out.println(0);
break;
case "top":
if (!stack.isEmpty()) {
System.out.println(-1);
break;
}
System.out.println(stack.peek());
break;
default:
int num = Integer.parseInt(input.split(" ")[1]);
stack.push(num);
}
}
}
}
역시나...
놀랍지 않다
근데 EmptyStack?? 뭔가 잘못 읽고 있나
package Week02.BJ_10828;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Stack<Integer> stack = new Stack<>();
int N = Integer.parseInt(br.readLine());
for (int i = 0; i < N; i++) {
String input = br.readLine();
switch (input) {
case "pop":
if (stack.isEmpty()) {
System.out.println(-1);
break;
}
System.out.println(stack.pop());
break;
case "size":
System.out.println(stack.size());
break;
case "empty":
if (stack.isEmpty()) {
System.out.println(1);
break;
}
System.out.println(0);
break;
case "top":
if (stack.isEmpty()) {
System.out.println(-1);
break;
}
System.out.println(stack.peek());
break;
default:
int num = Integer.parseInt(input.split(" ")[1]);
stack.push(num);
}
}
}
}
아 어이없다
if (stack.isEmpty()) 에서 ! 붙였음
+break 안 함
그런데 empty일 떄를 if 거는 게 좋은건지 empty 아닐 때 if 거는 게 좋은 건지 궁금하다
이건 지피티의 도움을 받아보기로...
💡 stack.isEmpty() vs !stack.isEmpty() 어디에 if를 거는 게 좋은가?
✅ 핵심 질문:
스택이 비어있을 때를 if로 거는 게 좋을까? 아니면 비어있지 않을 때를 if로 거는 게 좋을까?
🔍 정답은 상황에 따라 달라지지만, 대부분은 "정상적인 경우를 먼저 처리하는 방식"이 좋습니다.
🔸 예를 들어 pop 명령어의 경우:
if (stack.isEmpty()) {
System.out.println(-1);
} else {
System.out.println(stack.pop());
}
이 코드는 예외적인 상황(비었을 때) 를 먼저 처리하고,
정상 흐름은 뒤에 나오기 때문에 가독성은 좋음.
→ 에러/예외를 먼저 거르고 정상 흐름을 이어가는 패턴이라 자주 사용됨.
🔸 반대로 이렇게도 가능:
if (!stack.isEmpty()) {
System.out.println(stack.pop());
} else {
System.out.println(-1);
}
이건 정상 흐름을 먼저 보여주고, 예외를 나중에 처리
→ 뭔가 자연스러워 보이긴 하는데, 중첩된 로직이 많거나 분기 처리가 많을 때는 오히려 복잡해질 수 있음
✅ 정리하면:
if (stack.isEmpty()) 먼저 처리 | 예외 처리 먼저 → 코드 안정성, 가독성 ↑ | 정상 로직이 아래로 밀림 | 예외가 자주 나올 수 있는 상황, 복잡한 로직 |
if (!stack.isEmpty()) 먼저 처리 | 정상 흐름 강조 | 예외 처리가 뒤로 밀려서 놓칠 수 있음 | 로직이 단순하고, 예외 발생 가능성이 낮은 경우 |
👉 실무/코딩테스트 기준 팁:
- 예외 상황이 중요하거나 자주 발생할 수 있으면 isEmpty()를 먼저 처리하세요.
- 정상적인 흐름을 보여주는 게 가독성에 좋다고 판단되면 !isEmpty()를 먼저 써도 무방합니다.
- 코딩 테스트에선 "틀리지 않는 것" > "미묘한 스타일" 이므로 본인이 더 명확히 이해되는 방향으로 쓰는 게 가장 좋습니다.
그렇다고 합니다... 코드 스타일인 걸로~
일단 난 예외 처리가 더 나은 것 같아서 isEmpty() 로 써야겠다.
그러면 스택 공부해보기.
📦 스택(Stack)
스택은 데이터를 쌓는 자료구조로, 후입선출 (LIFO, Last In First Out) 방식으로 동작합니다.
즉, 마지막에 넣은 데이터가 가장 먼저 나간다.
상자 들어오는 대로 구덩이에다가 위로 겁내 쌓아 놓고 맨 위에 거부터 뺀다고 생각하면 될 것 같다... 편의점이나 마트에서 절대 하면 안 되는 일
🛠 주요 연산
push(x) | x를 스택에 넣기 |
pop() | 스택의 가장 위(top) 요소를 꺼냄 (제거됨) |
top() or peek() | 가장 위 요소를 확인 (제거 안 함) |
isEmpty() | 스택이 비어있는지 확인 |
size() | 스택 안에 있는 요소 개수 |
연산은 굉장히 직관적이다
자료구조 시간에 푸쉬팝,, 흠,,, 하고 속으로 생각했던 게 떠오름,,
pop()을 했을 때 가장 위 요소가 꺼내지면서 제거된다고 생각하면 된다. 보기만 할 거면 top() 이나 peek() 을 쓴다,,
빈 스택을 연산하면 에러가 나기 때문에 꼭 isEmpty() 확인해주기
📋 예시
Stack<Integer> stack = new Stack<>();
stack.push(1); // [1]
stack.push(2); // [1, 2]
stack.push(3); // [1, 2, 3]
stack.pop(); // 3 → [1, 2]
stack.peek(); // 2
stack.size(); // 2
📌 언제 쓰나?
- 웹 브라우저 뒤로 가기 기능
- 재귀 호출 구현 (함수 호출이 쌓였다가 돌아오는 구조)
- 괄호 검사, 문자열 계산기
- 깊이 우선 탐색(DFS)
- 수식 계산기 (후위표기법)
💡 스택의 특징 정리
- 마지막에 넣은 게 제일 먼저 나감 (LIFO)
- 한쪽(top)에서만 삽입/삭제 가능
- 배열(Array), 연결 리스트(LinkedList), 혹은 ArrayDeque로도 구현 가능
- Java에선 Stack<T> 클래스 제공되지만, 요즘은 Deque<T>로 구현하는 게 더 권장됨 (성능상 이유)
-> ???
머냐 왜???
📦 왜 Stack은 느릴까?
Stack은 Java 1.0 때부터 존재하는 클래스로, 내부적으로 Vector를 상속받아 만들었습니다.
public class Stack<E> extends Vector<E>
Vector는 모든 메서드에 synchronized 키워드가 붙어 있어서 멀티스레드 환경에선 안전하지만, 성능이 느립니다.
하지만 대부분의 스택 사용은 단일 스레드 환경이 많기 때문에, 불필요한 동기화는 성능만 깎아먹어요.
여기다가 더 찾아보니까 엄청 오래된 Vector를 상속받아서 쓰는 거라,,
취약점도 많고 부모 메소드인 Vector의 add 메소드 또한 사용 가능하게 되어 의도치 않은 동작이 실행될 수도 있다고 함
🚀 그래서 등장한 게 Deque
Java 1.6 이후부터는 Deque 인터페이스와 그 구현체 ArrayDeque, LinkedList가 제공됩니다.
Deque<Integer> stack = new ArrayDeque<>();
이건 동기화가 없기 때문에 빠르고,
양쪽에서 삽입/삭제가 가능해서 스택(LIFO) 도 되고, 큐(FIFO) 도 됩니다.
✅ 요약 정리
- Stack<T> = 구식, 느림, Vector 상속 (thread-safe)
- ArrayDeque<T> = 최신, 빠름, 동기화 없음 (싱글 스레드에 최적)
💡 "단일 스레드에서 스택처럼 쓰고 싶다!" → 무조건 ArrayDeque!
결론: 덱 써라
+
default 지우고 push 넣어서 명확하게 코드 수정
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Stack<Integer> stack = new Stack<>();
int N = Integer.parseInt(br.readLine());
for (int i = 0; i < N; i++) {
String[] input = br.readLine().split(" ");
switch (input[0]) {
case "push":
int num = Integer.parseInt(input[1]);
stack.push(num);
break;
case "pop":
if (stack.isEmpty()) {
System.out.println(-1);
break;
}
System.out.println(stack.pop());
break;
case "size":
System.out.println(stack.size());
break;
case "empty":
if (stack.isEmpty()) {
System.out.println(1);
break;
}
System.out.println(0);
break;
case "top":
if (stack.isEmpty()) {
System.out.println(-1);
break;
}
System.out.println(stack.peek());
break;
}
}
}
}
'백준 풀기' 카테고리의 다른 글
백준 10866번: 덱 with Java (0) | 2025.04.20 |
---|---|
백준 10845번: 큐 with Java (1) | 2025.04.19 |
백준 17087번: 숨바꼭질 6 with Java (1) | 2025.04.17 |
백준 4963번: 섬의 개수 with Java (0) | 2024.08.25 |
백준 10799번: 쇠막대기 with Java (0) | 2024.08.24 |