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

Stranger's LAB

페이지 맨 위로 올라가기

Stranger's LAB

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

[백준] 1021번 : 회전하는 큐 - JAVA [자바]

  • 2021.02.27 19:24
  • JAVA - 백준 [BAEK JOON]/큐, 덱
글 작성자: ST_
728x90





 
www.acmicpc.net/problem/1021

 

1021번: 회전하는 큐

첫째 줄에 큐의 크기 N과 뽑아내려고 하는 수의 개수 M이 주어진다. N은 50보다 작거나 같은 자연수이고, M은 N보다 작거나 같은 자연수이다. 둘째 줄에는 지민이가 뽑아내려고 하는 수의 위치가

www.acmicpc.net

 

 









  • 문제



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 





  • 알고리즘 [접근 방법]

 



 

 

 

이 문제는 덱(Deque)에 대한 이해만 있다면 크게 어렵지 않다.

 

혹여 덱(Deque)에 대해 자세하게 알고싶다면 다음 글을 참고하면 도움이 될 것이다.

 

st-lab.tistory.com/185

 

자바 [JAVA] - 배열을 이용한 Deque (덱) 구현하기

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

st-lab.tistory.com

 

st-lab.tistory.com/187

 

자바 [JAVA] - 연결리스트를 이용한 Deque (덱) 구현하기

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

st-lab.tistory.com

 

 

 

 

 

그러면 문제를 한 번 보자.

 

문제에서는 세 가지 연산이 주어졌다.

 

 

 

1. 첫 번째 원소를 뽑아낸다. 이 연산을 수행하면, 원래 큐의 원소가 a1, ..., ak이었던 것이 a2, ..., ak와 같이 된다.

 

이 부분은 다음과 같다고 보면 된다.

 

 

 

 

2. 왼쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 a2, ..., ak, a1이 된다.

 

 

 

 

 

3. 오른쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 ak, a1, ..., ak-1이 된다.

 

 

 

 

 

 

 

 

 

이렇게 세 가지 연산이 주어지고 문제에서 중요한 것은 '2번 연산과 3번 연산이 최소가 되도록' 해야 한다는 점이다.

 

 

 

 

그리고 두 번째 라인에는 뽑고자 하는 숫자를 입력받는다.

그리고 두 번쨰 라인에서 숫자를 뽑을 때 2번 또는 3번 연산을 최소한으로 이용하여 뽑아야 한다는 것이 포인트다.

 

 

 

즉, 위의 예시로 보자면 아래와 같다.

 

[예시 1]

 

Deque = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

뽑을 숫자 : 1, 2, 3

 

-> 1번 연산을 3번 하면 됨. 즉, 2번 연산과 3번 연산은 사용 안하기 떄문에 0 출력

 

 

[예시 2]

 

Deque = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

뽑을 숫자 : 2, 9, 5

count : 2번과 3번연산 누적 횟수 

 

과정 1-1 : 2는 현재 덱에서 중앙 보다 앞에 존재하기 때문에 2를 뽑기 위해 2번 연산(앞에 있는 수를 뒤로 보냄)을 한 번 실행

<Result> 

Deque = {2, 3, 4, 5, 6, 7, 8, 9, 10, 1}

count = 1

 

과정 1-2 : 2를 뽑음.

<Result> 

Deque = {3, 4, 5, 6, 7, 8, 9, 10, 1}

count = 1

 

 

과정 2-1 : 9는 현재 덱에서 중앙 보다 뒤에 있기 때문에 9를 뽑기 위해 3번 연산(뒤에 있는 수를 앞으로 보냄)을 세 번 실행

<Result> 

Deque = {9, 10, 1, 3, 4, 5, 6, 7, 8}

count = 4

 

과정 1-2 : 9를 뽑음.

<Result> 

Deque = {10, 1, 3, 4, 5, 6, 7, 8}

count = 4

 

 

 

과정 3-1 : 5는 현재 덱에서 뒤에 있기 때문에 5를 뽑기 위해 3번 연산(뒤에 있는 수를 앞으로 보냄)을 네 번 실행

(물론 2번연산을 네 번 실행해도 된다. 다만 가독성을 위해 3번 연산을 하기로 한다.)

<Result> 

Deque =  {5, 6, 7, 8, 10, 1, 3, 4}

count = 8

 

과정 1-2 : 5를 뽑음.

<Result> 

Deque = {6, 7, 8, 10, 1, 3, 4}

count = 8

 

결과 : 8

 

 

 

이런 식이다.

 

 

즉, 전체 과정으로 보자면 두 가지 프로세스를 거친다.

 

1. 뽑고자 하는 원소가 덱의 중앙에서 끝쪽에 가까운 쪽 방향으로 이동(연산)하여 뽑고자 하는 원소가 첫 번째 위치에 갈 때까지 반복

2. 원소를 뽑음

 

 

 

이 두가지 프로세스를 구현해주면 된다.

 

 

 

 

 

 

 

 





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

 



 

이전 포스팅과 여타 다를 바 없이 아래와 같이 두 가지 입력 방법을 통해 성능을 비교해보려한다.

참고로 Deque 자료구조는 LinkedList를 활용하여 구현하도록 하겠다. (찾고자 하는 원소의 위치를 쉽게 얻기 위함)

 

자세한 내용은 코드를 보면서 이해할 수 있도록 주석으로 상세하게 달아놓겠다.

 

 

1. Scanner

2. BufferedReader

 

 

 

 






  • 풀이





- 방법 1 : [Scanner]

 

import java.util.Scanner;
import java.util.LinkedList;

public class Main {

	public static void main(String[] args) {
		
		Scanner in = new Scanner(System.in);
		
		LinkedList<Integer> deque = new LinkedList<Integer>();
		
		int count = 0;	// 2, 3번 연산 횟수 누적 합 변수
		
		int N = in.nextInt();	// 큐의 크기(1 ~ N)
		int M = in.nextInt();	// 뽑으려는 숫자의 개수
		
		// 1부터 N까지 덱에 담아둔다.
		for(int i = 1; i <= N; i++) {
			deque.offer(i);
		}
		
		int[] seq = new int[M];	// 뽑고자 하는 수를 담은 배열
		
		for(int i = 0; i < M; i++) {
			seq[i] = in.nextInt();
		}
		
		
		for(int i = 0; i < M; i++) {			
			
			// 덱에서 뽑고자 하는 숫자의 위치(index) 찾기 
			int target_idx = deque.indexOf(seq[i]);
			int half_idx;
			/*
			 *  만약 현재 덱의 원소가 짝수 개라면 중간 지점을 
			 *  현재 덱의 절반 크기에서 -1 감소시킨다. 
			 *  
			 *  {1, 2, 3, 4} 일 때, 2를 중간지점으로 하면
			 *  인덱스는 1이기 때문
			 */
			if(deque.size() % 2 == 0) {
				half_idx = deque.size() / 2 - 1;
			}
			else {
				half_idx = deque.size() / 2;
			}
			
			
			// 중간 지점 또는 중간 지점보다 원소의 위치가 앞에 있을 경우
			if(target_idx <= half_idx) {
				// idx 보다 앞에 있는 원소들을 모두 뒤로 보낸다. (2번 연산)
				for(int j = 0; j < target_idx; j++) {
					int temp = deque.pollFirst();
					deque.offerLast(temp);
					count++;
				}
			}
			else {	// 중간 지점보다 원소의 위치가 뒤에 있는 경우 
				// idx를 포함한 뒤에 있는 원소들을 모두 앞으로 보낸다. (3번 연산)
				for(int j = 0; j < deque.size() - target_idx; j++) {
					int temp = deque.pollLast();
					deque.offerFirst(temp);
					count++;
				}
			
			}
			deque.pollFirst();	// 연산이 끝나면 맨 앞 원소를 삭제
		}
		
		System.out.println(count);
		
		
	}
}

 

 

 

 

생각한 것 보다 코드가 그리 길지도 않고 구현이 어렵지 않은 것을 볼 수 있다.

 

 

 











- 방법 2 : [BufferedReader]

 

 

 

입력 방법을 Scanner 대신 BufferedReader 을 사용하여 풀이하는 방법이다. 단, BufferedReader 는 문자열을 한 줄로 읽기 때문에 N과 M, 그리고 두 번째 줄의 수들을 구분하기 위해 공백을 기준으로 문자열을 분리해주어야하니 StringTokenizer 을 사용하여 풀도록 하겠다.

 

 

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

import java.util.LinkedList;
import java.util.StringTokenizer;

public class Main {

	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		LinkedList<Integer> deque = new LinkedList<Integer>();
		
		int count = 0;	// 2, 3번 연산 횟수 누적 합 변수
		
		StringTokenizer st = new StringTokenizer(br.readLine(), " ");
		int N = Integer.parseInt(st.nextToken());	// 큐의 크기(1 ~ N)
		int M = Integer.parseInt(st.nextToken());	// 뽑으려는 숫자의 개수
		
		// 1부터 N까지 덱에 담아둔다.
		for(int i = 1; i <= N; i++) {
			deque.offer(i);
		}
		
		int[] seq = new int[M];	// 뽑고자 하는 수를 담은 배열
		
		st = new StringTokenizer(br.readLine(), " ");
		for(int i = 0; i < M; i++) {
			seq[i] = Integer.parseInt(st.nextToken());
		}
		
		
		for(int i = 0; i < M; i++) {
			
			
			// 덱에서 뽑고자 하는 숫자의 위치(index) 찾기 
			int target_idx = deque.indexOf(seq[i]);
			int half_idx;
			/*
			 *  만약 현재 덱의 원소가 짝수 개라면 중간 지점을 
			 *  현재 덱의 절반 크기에서 -1 감소시킨다. 
			 *  
			 *  {1, 2, 3, 4} 일 때, 2를 중간지점으로 하면
			 *  인덱스는 1이기 때문
			 */
			if(deque.size() % 2 == 0) {
				half_idx = deque.size() / 2 - 1;
			}
			else {
				half_idx = deque.size() / 2;
			}
			
			
			// 중간 지점 또는 중간 지점보다 원소의 위치가 앞에 있을 경우
			if(target_idx <= half_idx) {
				// idx 보다 앞에 있는 원소들을 모두 뒤로 보낸다. (2번 연산)
				for(int j = 0; j < target_idx; j++) {
					int temp = deque.pollFirst();
					deque.offerLast(temp);
					count++;
				}
			}
			else {	// 중간 지점보다 원소의 위치가 뒤에 있는 경우 
				// idx를 포함한 뒤에 있는 원소들을 모두 앞으로 보낸다. (3번 연산)
				for(int j = 0; j < deque.size() - target_idx; j++) {
					int temp = deque.pollLast();
					deque.offerFirst(temp);
					count++;
				}
			
			}
			deque.pollFirst();	// 연산이 끝나면 맨 앞 원소를 삭제
		}
		
		System.out.println(count);
		
		
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 





  • 성능




 



 

채점 번호 : 26804927  -  방법 2 : BufferedReader

채점 번호 : 26804925  -  방법 1 : Scanner

 

 

입력의 경우 Scanner 보다는 BufferedReader 가 빠른 걸 볼 수 있다.




 





  • 정리

 



 

 

쓰고자 하는 자료구조를 적절히 선택해서 쓰면 되는 문제라 이 번 문제는 크게 어려운 점이 없었을 것이다. 정답률도 높은 것을 보니..

 

혹여나 이해가 안되거나 어려운 부분이 있다면 언제든 댓글 달아주시면 감사하겠다 :)

 

 

 



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

'JAVA - 백준 [BAEK JOON] > 큐, 덱' 카테고리의 다른 글

[백준] 5430번 : AC - JAVA [자바]  (20) 2021.03.07
[백준] 10866번 : 덱 - JAVA [자바]  (8) 2021.02.19
[백준] 1966번 : 프린터 큐 - JAVA [자바]  (10) 2021.02.03
[백준] 11866번 : 요세푸스 문제 0 - JAVA [자바]  (10) 2021.01.23
[백준] 2164번 : 카드2 - JAVA [자바]  (4) 2020.12.19

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [백준] 5430번 : AC - JAVA [자바]

    [백준] 5430번 : AC - JAVA [자바]

    2021.03.07
  • [백준] 10866번 : 덱 - JAVA [자바]

    [백준] 10866번 : 덱 - JAVA [자바]

    2021.02.19
  • [백준] 1966번 : 프린터 큐 - JAVA [자바]

    [백준] 1966번 : 프린터 큐 - JAVA [자바]

    2021.02.03
  • [백준] 11866번 : 요세푸스 문제 0 - JAVA [자바]

    [백준] 11866번 : 요세푸스 문제 0 - JAVA [자바]

    2021.01.23
다른 글 더 둘러보기

정보

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_.

티스토리툴바