백준 풀기

백준 10828번: 스택 with Java

삼겹살파튀 2025. 4. 18. 16:17

스택

 
시간 제한메모리 제한제출정답맞힌 사람정답 비율
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;
            }
        }
    }
}