1. 문제
스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.
1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.
입력
첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.
출력
입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.
예제 입력 1
8
4
3
6
8
7
5
2
1
예제 출력 1
+
+
+
+
-
-
+
+
-
+
+
-
-
-
-
-
예제 입력 2
5
1
2
5
3
4
예제 출력 2
NO
2 - 1. 나의 풀이
순서를 int 배열에 저장
stack에 push하면서 int배열에 값이 나오면 pop
* String answer =""; 선언 후 answer += 를 계속하면 메모리초과가 난다.
String은 Imutable 길이가 변하지 않는다.
즉, String 문자열에 문자를 이어 붙이는 건 문자열이 변하는것이 아니라 새로운 문자열 객체를 생성한 후 참조하는 것이다.
이 과정을 계속 하다보면 메모리 초과가난다.
그러므로 문자열을 변화하는 StringBuilder를 사용하면 메모리 초과 문제가 해결된다.
하지만 나의 방식은 효율적인 풀이는 아니다 메모리를 많이 잡아먹는다.
그 이유는 수열이 불가능한 경우를 오름차순으로 증가하는 num이 n까지 도달해야 알 수 있기 때문이다.
이를 보완한 다른 효율적인 풀이가 있다.
2 - 2. 나의 풀이
package solvedac;
import java.util.*;
public class ac1874 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //수의 개수
int[] arr = new int[n];
for(int i = 0;i<n ;i++) arr[i] = sc.nextInt();
Stack<Integer> st = new Stack<>();
st.push(1);
StringBuilder sb = new StringBuilder();
sb.append("+\n");
int num=2;
int index=0;
while(index < n){
if(st.isEmpty() || st.peek() != arr[index]){ //스택 윗부분과 배열 값이 같으면 스택에서 꺼낸다.
st.push(num);
num++;
sb.append("+\n");
}else{
index++;
st.pop();
sb.append("-\n");
}
if(num > n+1){
sb = new StringBuilder("NO");
break;
}
}
System.out.println(sb.toString());
}
}
3 - 1. 다른 풀이
설명을 너무 잘해놔서 복붙 후 출처 남김
https://st-lab.tistory.com/182
[백준] 1874번 : 스택 수열 - JAVA [자바]
www.acmicpc.net/problem/1874 1874번: 스택 수열 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]을 얻을 수 있
st-lab.tistory.com
예제에서의 처음 수열 입력값은 '4'다. (8은 입력의 개수이므로 제외)
그럼 1부터 4까지의 정수를 스택에 push한다.
int start = 0;
/* ------N번 반복----- */
int value = input();
if(value > start) {
for(int i = start + 1; i <= value; i++) {
stack.push(i);
}
start = value;
}
그리고 숫자를 push 할 때는 반드시 오름차순이어야 하기 때문에 이전에 어디까지 입력 받았는지를 알기 위한 변수 start를 value 값으로 초기화 해주어야 한다. (4까지 push했기 때문에 다음에 push 할 경우 5 부터 push하기 위함이다.)
그런 다음 스택의 맨 위 원소가 입력받은 4와 같다면 pop을 해주고, 만약 같지 않다면 주어진 수열을 만족하지 못하는 것이므로 "NO" 가 된다.
int start = 0;
/* ------N번 반복----- */
int value = input();
if(value > start) {
for(int i = start + 1; i <= value; i++) {
stack.push(i);
}
start = value;
}
// top에 있는 원소가 입력받은 값과 같이 않은 경우
else if(stack.peek() != value) {
print("NO");
return; // 더이상 탐색 할 필요가 없으므로 프로그램을 종료시켜 버린다.
}
// value 값까지 push가 되어있다면 pop을 해준다.
stack.pop();
3 - 2. 다른 코드
import java.util.Scanner;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
StringBuilder sb = new StringBuilder(); // 출력할 결과물 저장
Stack<Integer> stack = new Stack<>();
int N = in.nextInt();
int start = 0;
// N 번 반복
while(N -- > 0) {
int value = in.nextInt();
if(value > start) {
// start + 1부터 입력받은 value 까지 push를 한다.
for(int i = start + 1; i <= value; i++) {
stack.push(i);
sb.append('+').append('\n'); // + 를 저장한다.
}
start = value; // 다음 push 할 때의 오름차순을 유지하기 위한 변수 초기화
}
// top에 있는 원소가 입력받은 값과 같이 않은 경우
else if(stack.peek() != value) {
System.out.println("NO");
return; // 또는 System.exit(0); 으로 대체해도 됨.
}
stack.pop();
sb.append('-').append('\n');
}
System.out.println(sb);
}
}
4. 얻어갈 점
1. String에 += 하면 메모리상 안좋은 이유.
2. 스택 공부
'자바 알고리즘 문제풀이 > 백준' 카테고리의 다른 글
백준 1003번 피보나치 함수 (2) | 2023.12.28 |
---|---|
백준 1966번 프린터 큐 (2) | 2023.12.12 |
백준 1676 팩토리얼 0의 개수 (2) | 2023.12.05 |
백준 1654번 랜선 자르기 (1) | 2023.12.03 |
백준 1181번 단어 정렬 (0) | 2023.11.29 |