이 영역을 누르면 첫 페이지로 이동
Stranger's LAB 블로그의 첫 페이지로 이동

Stranger's LAB

페이지 맨 위로 올라가기

Stranger's LAB

프로그래밍과 관련하여 다양한 알고리즘 문제를 풀어보고, 프로그래밍 언어를 이해해 볼 수 있도록 돕고자 만든 블로그 입니다.

[백준] 1874번 : 스택 수열 - JAVA [자바]

  • 2020.12.03 23:14
  • JAVA - 백준 [BAEK JOON]/스택
글 작성자: ST_
728x90






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]을 얻을 수 있다.

www.acmicpc.net

 

 









  • 문제



 

 

 

 

 

스택의 원리만 이해한다면 쉽게 풀 수 있는 문제다.

 

 

 

 

 

 

 

 





  • 알고리즘 [접근 방법]

 



 

아마 이 문제를 처음 접한다면 무슨 말인가 할 수도 있겠지만, 이해만 한다면 정말 쉬운 문제다.

 

스택 자료구조는 본문에서도 나와있듯이 LIFO(후입선출) 특성을 갖고있다. 스택에 대한 기본적인 이해는 다음 포스팅을 참고하시길 바란다.

 

 

자바 [JAVA] - Stack (스택) 구현하기

•자료구조 관련 목록 링크 펼치기 더보기 0. 자바 컬렉션 프레임워크 (Java Collections Framework) 1. 리스트 인터페이스 (List Interface) 2. 어레이리스트 (ArrayList) 3. 단일 연결리스트 (Singly LinkedLi..

st-lab.tistory.com

 

 

 

그럼 문제를 살펴보도록 하자.

 

스택에 1 부터 n까지 수를 스택에 넣고(push) 빼는(pop) 과정을 통해 임의의 수열이 주어졌을 때 해당 수열을 만들 수 있는지를 판단하는 문제다.

 

이 때 스택에 수를 넣을 때(push)는 반드시 오름차순을 지켜야 한다.

 

무슨 말인가 이해하기 어렵다면 예제로 한 번 보면 이렇다.

 

 

 

이런 식의 과정을 거치게 된다.

 

 

그럼 어떻게 풀어야 할까?

 

예제에서의 처음 수열 입력값은 '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();

 

 

 

위 구조를 조금 가다듬어서 전체적으로 반복을 하면 된다.

 

전체적으로 보면 입력받은 value 값 까지 push 한 이력이 없을경우 stack에 value까지 push 한 후 마지막 원소를 pop해주면 되는 문제다. 참고로 결과적으로 출력해야 할 것은 + 또는 - 이므로 StringBuilder 을 사용하여 push할 땐 '+'를, pop할 때는 '-' 를 저장해준 뒤 만약 반복문이 정상적으로 끝날 경우 저장해둔 문자열을 한 번에 출력해주고, 그 외의 경우 이미 "NO"가 출력되어 프로그램이 종료된 상태이므로 출력될 일이 없다.

 

자세한 건 아래 풀이에서 알 수 있을 것이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 





  • 4가지 방법을 사용하여 풀이한다.

 



이전 포스팅과 여타 다를 바 없이 스택 라이브러리를 사용하는 방법과 배열을 선언하여 스택처럼 사용하는 방법을 보여주고자 한다.

그리고 각각의 방법에 입력 방법을 달리하여 성능을 비교해보려 한다.

 

1 . Scanner + Stack

2. BufferedReader + Stack

1 . Scanner + array

2. BufferedReader + array

 

 

 

 






  • 풀이





- 방법 1 : [Scanner + Stack]

 

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);
	}
}

 

 

보면 필자가 위 알고리즘 설명과 크게 다를 것이 없다. 추가 된 것이 있다면 StringBuilder을 이용하여 문자열을 연결해주는 작업만 추가되었을 뿐이다.

 

 

 

 











- 방법 2 : [BufferedReader + StringBuilder]

 

 

 

입력 방법을 Scanner 대신 BufferedReader 을 사용하여 풀이하는 방법이다.

 

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Stack;

public class Main {
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();	// 출력할 결과물 저장
		
		Stack<Integer> stack = new Stack<>();
		
		int N = Integer.parseInt(br.readLine());
		
		int start = 0;
		
		// N 번 반복
		while(N -- > 0) {
			
			int value = Integer.parseInt(br.readLine());
			
			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);
	}
}

 

 

 

크게 어려울 것은 없을 것이다. 이번 문제는 중복을 고려하지 않아도 되니 오히려 쉬웠을 수도 있다.

 

 

 

 











- 방법 3 : [Scanner + array]

 

 

 

 

Stack 클래스 대신 stack 자료구조를 배열로 직접 구현하여 풀이하는 방법이다.

 

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		
		StringBuilder sb = new StringBuilder();	// 출력할 결과물 저장 
        
		int N = in.nextInt();
		
		int[] stack = new int[N];
		
		int idx = 0;
		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[idx] = i;
					idx++;
					sb.append('+').append('\n');
				}
				start = value; 	// 다음 push 할 때의 오름차순을 유지하기 위한 변수 초기화 
			}
			
			// top에 있는 원소가 입력받은 값과 같이 않은 경우  
			else if(stack[idx - 1] != value) {
					System.out.println("NO");
					System.exit(0);	//	return 으로 대체해도 됨 
			}
			
			idx--;
			sb.append('-').append('\n');
		}
		System.out.println(sb);
	}

}

 

 

 

배열로 구성하는 방법이다. 배열로 작성하더라도 스택 자료구조의 기본 개념과 같기 때문에 그대로 구현 원리만 따라주면 된다.

 

 











- 방법 4 : [BufferedReader + array]

 

 

 

 

방법 3에서 입력 방법만 바꾼 방법이다.

 

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main {

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		StringBuilder sb = new StringBuilder();
		int N = Integer.parseInt(br.readLine());
		
		int[] stack = new int[N];
		
		int idx = 0;
		int start = 0;
		
		// N 번 반복
		while(N -- > 0) {
			int value = Integer.parseInt(br.readLine());
			
			if(value > start) {
				// start + 1부터 입력받은 value 까지 push를 한다.
				for(int i = start + 1; i <= value; i++) {
					stack[idx] = i;
					idx++;
					sb.append('+').append('\n');
				}
				start = value; 	// 다음 push 할 때의 오름차순을 유지하기 위한 변수 초기화 
			}
			
			// top에 있는 원소가 입력받은 값과 같이 않은 경우  
			else if(stack[idx - 1] != value) {
					System.out.println("NO");
					System.exit(0);	//	return 으로 대체해도 됨 
			}
			
			idx--;
			sb.append('-').append('\n');
		}
		System.out.println(sb);
	}

}

 

 

 

 

 

 

 

 

 





  • 성능






 

 

채점 번호 : 24193328  -  방법 4 : BufferedReader + array

채점 번호 : 24193320  -  방법 3 : Scanner + array

채점 번호 : 24193313  -  방법 2 : BufferedReader + Stack

채점 번호 : 24192998  -  방법 1 : Scanner + Stack

 

 

 








  • 정리

 



이 번 문제 또한 어려운 점은 없었을 것이다. 만약 어려웠던 점이 있다면 이러한 문제를 처음 접하는 분들은 어떤 말인지 지문을 이해하는 것이 아니었을까 생각이 든다.

 

여튼 이 문제로 스택 자료구조 카테고리의 문제는 끝났다.

하지만 안타깝게도 다음 문제 또한 자료구조와 관련 된 카테고리다. 큐(Queue)와 덱(Deque)인데 쉽게 생각하자면, 큐는 단방향 대기열이고, 덱은 양방향 대기열이라고 보면 된다.

 

큐 자료구조는 여러모로 쓰일 일이 많기 때문에 문제를 풀기 전에 어떤 원리로 짜여져 있는지부터 이해하는 것이 중요하다.

필자도 Queue 자료구조를 먼저 구현 한 뒤 백준 큐, 덱 카테고리를 진행하고자 한다.

 

 

만약 어렵거나 이해가 안되는 부분이 있다면 언제든 댓글 남겨주시면 된다.

 

 

 



저작자표시 비영리 변경금지 (새창열림)

'JAVA - 백준 [BAEK JOON] > 스택' 카테고리의 다른 글

[백준] 4949번 : 균형잡힌 세상 - JAVA [자바]  (11) 2020.12.01
[백준] 9012번 : 괄호 - JAVA [자바]  (18) 2020.11.30
[백준] 10773번 : 제로 - JAVA [자바]  (5) 2020.11.27
[백준] 10828번 : 스택 - JAVA [자바]  (32) 2020.11.20

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [백준] 4949번 : 균형잡힌 세상 - JAVA [자바]

    [백준] 4949번 : 균형잡힌 세상 - JAVA [자바]

    2020.12.01
  • [백준] 9012번 : 괄호 - JAVA [자바]

    [백준] 9012번 : 괄호 - JAVA [자바]

    2020.11.30
  • [백준] 10773번 : 제로 - JAVA [자바]

    [백준] 10773번 : 제로 - JAVA [자바]

    2020.11.27
  • [백준] 10828번 : 스택 - JAVA [자바]

    [백준] 10828번 : 스택 - JAVA [자바]

    2020.11.20
다른 글 더 둘러보기

정보

Stranger's LAB 블로그의 첫 페이지로 이동

Stranger's LAB

  • Stranger's LAB의 첫 페이지로 이동

검색

나의 외부 링크

  • st-github

공지사항

  • 공지 - 블로그 사용 설명서

메뉴

  • 홈
  • 방명록

카테고리

  • 전체 카테고리 (267)
    • Java (5)
    • JAVA - 백준 [BAEK JOON] (177)
      • 입출력과 사칙연산 (14)
      • 조건문 (7)
      • 반복문 (11)
      • 1차원 배열 (7)
      • 함수 (3)
      • 문자열 (10)
      • 기본 수학 1 (8)
      • 기본 수학 2 (6)
      • 2차원 배열 (0)
      • 정렬 (10)
      • 재귀 (4)
      • 브루트 포스 (5)
      • 집합과 맵 (0)
      • 기하 1 (5)
      • 정수론 및 조합론 (12)
      • 백트래킹 (8)
      • 동적 계획법 1 (15)
      • 누적 합 (0)
      • 그리디 알고리즘 (5)
      • 스택 (5)
      • 큐, 덱 (7)
      • 분할 정복 (9)
      • 이분 탐색 (7)
      • 기타 문제 (17)
      • 별 찍기 문제 모음 (2)
    • C++ - 백준 [BAEK JOON] (46)
      • 입출력과 사칙연산 (14)
      • 조건문 (7)
      • 반복문 (11)
      • 1차원 배열 (7)
      • 함수 (3)
      • 문자열 (0)
      • 기타 문제 (4)
    • 자료구조 (18)
      • Java (18)
    • 알고리즘 (11)
      • Java (11)
    • 프로그래밍 기초 (6)
    • 이모저모 (2)
    • 일상의 글 (2)

최근 글

정보

ST_의 Stranger's LAB

Stranger's LAB

ST_

블로그 구독하기

  • 구독하기
  • 네이버 이웃 맺기
  • RSS 피드

방문자

  • 전체 방문자
  • 오늘
  • 어제

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © ST_.

티스토리툴바