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

Stranger's LAB

페이지 맨 위로 올라가기

Stranger's LAB

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

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

  • 2020.12.01 08:51
  • JAVA - 백준 [BAEK JOON]/스택
글 작성자: ST_
728x90





 
www.acmicpc.net/problem/4949

 

4949번: 균형잡힌 세상

하나 또는 여러줄에 걸쳐서 문자열이 주어진다. 각 문자열은 영문 알파벳, 공백, 소괄호("( )") 대괄호("[ ]")등으로 이루어져 있으며, 길이는 100글자보다 작거나 같다. 입력의 종료조건으로 맨 마

www.acmicpc.net

 

 









  • 문제



 

 

 

 

이전 괄호 문제에서 좀 더 업그레이드 된 버전이다.

 

 

 

 

 

 

 

 

 





  • 알고리즘 [접근 방법]

 



 

이 문제는 이 전 문제인 9012의 괄호 문제를 정확히 이해하고 있다면 쉽게 풀 수 있을 것이다. 만약 괄호 문제를 풀어보지 않았다면 먼저 아래 포스팅을 먼저 보고 오시길 바란다.

 

 

 

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

www.acmicpc.net/problem/9012 9012번: 괄호 괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올..

st-lab.tistory.com

 

 

 

 

 

 

 

우리가 괄호 문제에서 풀었을 때는 '(' 와 ')' 만 다루었었다.

 

이 때, 온전한 수식을 검사하는 코드를 다음과 같이 짰었다.

 

String s = input();	// 한 줄 입력
for(int i = 0; i < length; i++) {	// legnth는 문자열의 길이
 
	char c = s.charAt(i);	// i 번째 문자
    
	// 여는 괄호일 경우 스택에 넣는다.
	if(c == '(') {
		stack.push(c);
	}
 
	// 아래는 모두 닫는 괄호 일 경우들이다.
    
	// 스택이 비어있는 경우. 즉, 닫는 괄호를 입력받았으나 pop할 원소가 없을 경우
	else if(stack.empty()){
		return "NO";
	}
	// 그 외의 경우 stack 원소를 pop 한다.
	else {
		stack.pop();
	}
}
 
/*
 모든 검사 마치고 스택에 잔여 요소가 있으면 여는 괄호가 많은 경우는 "NO"
 스택이 비어있으면 온전한 수식이므로 "YES" 이다.
*/
 
if(stack.empty()) {
	return "YES";
}
else {
	return "NO";
}

 

 

그러면 위 문제에서 수정해야 할 것은 무엇일까?

 

먼저 이전 문제랑 달라진 점을 보자.

 

1. 대괄호 '[' 와 ']' 가 추가되었다.

2. 괄호와 상관 없는 문자들이 섞여있다.

 

우리가 균형잡힌 문자열인지 판단할 때 '괄호 문자'인지를 판단해야하고, 이 후  '여는 괄호'인지, '닫는 괄호'인지를 판단하며, 닫는 괄호 일 경우 ']' 의 경우는 '[' 과 매칭되어야 하고, ')' 의 경우는 '(' 과 매칭되어야 한다.

그리고 괄호가 아닌 문자의 경우에는 그냥 넘어가면 된다.

 

즉, 약간의 수정만하여 다음과 같이 짜면 된다.

 

String s = input();	// 한 줄 입력
for(int i = 0; i < s.length(); i++) {
			
	char c = s.charAt(i);	// i 번째 문자 
			
	// 여는 괄호일 경우 스택에 push 
	if(c == '(' || c == '[') {
		stack.push(c);
	}
			
	// 닫는 소괄호 일 경우 
	else if(c == ')') {
				
		// 스택이 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
		if(stack.empty() || stack.peek() != '(') {
			return "no";
		}
		else {
			stack.pop();
		}
	}
			
	else if(c == ']') {
				
		// 스택이 비어있거나 pop할 원소가 대괄호랑 매칭이 안되는 경우 
		if(stack.empty() || stack.peek() != '[') {
			return "no";
		}
		else {
			stack.pop();
		}
	}
			
	// 그 외의 경우에는 불필요한 문자들이기에 skip한다. 
}
		
if(stack.empty()) {
	return "yes";
}
else {
	return "no";
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 





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

 



위 에서 설명한 방법은 Stack 클래스를 사용한 방법이다. 위 알고리즘에서 Stack의 원리를 char[] 배열로도 구현할 수 있는데, 그리 어렵지도 않고, Stack 구현만 할 줄 안다면 매우 쉽게 풀이할 수 있는지라 따로 설명하지는 않았다.

 

즉, Stack클래스를 사용한 것과 char[] 배열을 사용한 방법에 각각 입력의 방법을 달리하여 풀어보기로 하겠다.

 

1. Scanner + Stack

2. BufferedReader + Stack

3 . Scanner + char[]

4. BufferedReader + char[]

 

 

 

 






  • 풀이





- 방법 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);

		String s;
		
		while(true) {		
			s = in.nextLine();
			
			if(s.equals(".")) {	// 종료 조건문 
				break;
			}		
			System.out.println(solve(s));
		}
	
	}
	
	public static String solve(String s) {
		
		Stack<Character> stack = new Stack<>();
		
		for(int i = 0; i < s.length(); i++) {
			
			char c = s.charAt(i);	// i 번째 문자 
			
			// 여는 괄호일 경우 스택에 push 
			if(c == '(' || c == '[') {
				stack.push(c);
			}
			
			// 닫는 소괄호 일 경우 
			else if(c == ')') {
				
				// 스택이 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
				if(stack.empty() || stack.peek() != '(') {
					return "no";
				}
				else {
					stack.pop();
				}
			}
			
			else if(c == ']') {
				
				// 스택이 비어있거나 pop할 원소가 대괄호랑 매칭이 안되는 경우 
				if(stack.empty() || stack.peek() != '[') {
					return "no";
				}
				else {
					stack.pop();
				}
			}
			
			// 그 외의 경우에는 불필요한 문자들이기에 skip한다. 
		}
		
		if(stack.empty()) {
			return "yes";
		}
		else {
			return "no";
		}
	}

}

 

 

가장 기본적인 방법이라 할 수 있겠다.

 

 

 











- 방법 2 : [BufferedReader + Stack]

 

 

 

입력 방법을 Scanner 대신 BufferedReader 을 사용하여 풀이하는 방법이다. 추가로 성능개선차 출력방법을 조금 다르게 StringBuilder를 사용하였다.

 

 

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

		String s;
		
		while(true) {
			
			s = br.readLine();
			
			if(s.equals(".")) {	// 종료 조건문 
				break;
			}
			
			sb.append(solve(s)).append('\n');
		}
		
		System.out.println(sb);
		
		
	}
	
	public static String solve(String s) {
		
		Stack<Character> stack = new Stack<>();
		
		for(int i = 0; i < s.length(); i++) {
			
			char c = s.charAt(i);	// i 번째 문자 
			
			// 여는 괄호일 경우 스택에 push 
			if(c == '(' || c == '[') {
				stack.push(c);
			}
			
			// 닫는 소괄호 일 경우 
			else if(c == ')') {
				
				// 스택이 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
				if(stack.empty() || stack.peek() != '(') {
					return "no";
				}
				else {
					stack.pop();
				}
			}
			
			else if(c == ']') {
				
				// 스택이 비어있거나 pop할 원소가 대괄호랑 매칭이 안되는 경우 
				if(stack.empty() || stack.peek() != '[') {
					return "no";
				}
				else {
					stack.pop();
				}
			}
			
			// 그 외의 경우에는 불필요한 문자들이기에 skip한다. 
		}
		
		if(stack.empty()) {
			return "yes";
		}
		else {
			return "no";
		}
	}

}

 

 

 

 

 

 

 











- 방법 3 : [Scanner + char[]]

 

 

 

스택 클래스 대신 배열을 선언하고 이를 스택처럼 사용하는 방법도 있다. 따로 설명은 하지 않았지만, 스택의 원리를 그대로 따라가기 때문에 코드만 보더라도 쉽게 이해할 수 있을 것이다.

 

 

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
    
		Scanner in = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		String s;

		while (true) {

			s = in.nextLine();

			if (s.equals(".")) { // 종료 조건문
				break;
			}

			sb.append(solve(s)).append('\n');
		}

		System.out.println(sb);
	}

	public static String solve(String s) {
		
		char[] stack = new char[s.length()];	// 스택처럼 사용할 비열 
		int size = 0;

		for (char val : s.toCharArray()) {
			
			// 여는 괄호일 경우 배열에 저장 후 size 1증가 
			if (val == '(' || val == '[') {
				stack[size] = val;
				size++;
			} 
			
			// 닫는 소괄호일경우 
			else if (val == ')') {
				
				// 요소가 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
				if (size == 0 || stack[size - 1] != '(') {
					return "no";
				} 
				else {
					size--;
				}
			} 
			
			// 닫는 소괄호일경우 
			else if (val == ']') {
				
				// 요소가 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
				if (size == 0 || stack[size - 1] != '[') {
					return "no";
				} 
				else {
					size--;
				}
			}
		}
		
		if (size != 0) {
			return "no";
		} 
		else {
			return "yes";
		}
	}
}

 

 

물론 pop할 때 char[] 배열에 명시적으로 문자를 0 값으로 치환해주어도 되나 size로 카운팅만 해주어도 크게 문제되진 않는다.

 

 

 











- 방법 4 : [BufferedReader + char[]]

 

 

 

방법 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();
		String s;

		while (true) {

			s = br.readLine();

			if (s.equals(".")) { // 종료 조건문
				break;
			}

			sb.append(solve(s)).append('\n');
		}

		System.out.println(sb);
	}

	public static String solve(String s) {
		
		char[] stack = new char[s.length()];	// 스택처럼 사용할 비열 
		int size = 0;

		for (char val : s.toCharArray()) {
			
			// 여는 괄호일 경우 배열에 저장 후 size 1증가 
			if (val == '(' || val == '[') {
				stack[size] = val;
				size++;
			} 
			
			// 닫는 소괄호일경우 
			else if (val == ')') {
				
				// 요소가 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
				if (size == 0 || stack[size - 1] != '(') {
					return "no";
				} 
				else {
					size--;
				}
			} 
			
			// 닫는 소괄호일경우 
			else if (val == ']') {
				
				// 요소가 비어있거나 pop할 원소가 소괄호랑 매칭이 안되는 경우 
				if (size == 0 || stack[size - 1] != '[') {
					return "no";
				} 
				else {
					size--;
				}
			}
		}
		
		if (size != 0) {
			return "no";
		} 
		else {
			return "yes";
		}
	}
}

 

 

 

 

 

 

 

 

 

 

 

 





  • 성능




 

 

 

채점 번호 : 24142208  -  방법 4 : BufferedReader + char[]

채점 번호 : 24142206  -  방법 3 : Scanner + char[]

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

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

 

 

입력의 경우는 확실히 Scanner 보다는 BufferedReader 가 빠른 걸 볼 수 있다. 또한 Stack 클래스를 쓰는 것보다는 단순 배열로 처리하는 것이 메모리나 처리 과정에서 단순화 되어있어 더 빠르다는 것을 볼 수 있다.

 

 








  • 정리

 



 

저 번 문제만 풀었다면 어렵지 않게 풀 수 있는 문제라 매우 쉽게 풀었을 것이다.

 

아마 스택의 원리를 이해하지 못하고 그냥 풀어서 그런지 정답률이 생각 외로 낮다만.. 만약 스택에 대해 궁금하다면 아래 포스팅을 참고하셔도 좋을 것 같다.

 

 

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

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

st-lab.tistory.com

 

혹여 어렵거나 이해가 가지 않는 부분이 있다면 댓글 남겨주시면 된다. 빠르게 답변드리도록 하겠다.

 

 



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

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

[백준] 1874번 : 스택 수열 - JAVA [자바]  (24) 2020.12.03
[백준] 9012번 : 괄호 - JAVA [자바]  (18) 2020.11.30
[백준] 10773번 : 제로 - JAVA [자바]  (5) 2020.11.27
[백준] 10828번 : 스택 - JAVA [자바]  (32) 2020.11.20

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

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

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

    2020.12.03
  • [백준] 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_.

티스토리툴바