본문 바로가기

알고리즘(Java)/덱

백준 1021번 회전하는 큐

문제

지민이는 N개의 원소를 포함하고 있는 양방향 순환 큐를 가지고 있다. 지민이는 이 큐에서 몇 개의 원소를 뽑아내려고 한다.

지민이는 이 큐에서 다음과 같은 3가지 연산을 수행할 수 있다.

  1. 첫번째 원소를 뽑아낸다. 이 연산을 수행하면, 원래 큐의 원소가 a1, ..., ak이었던 것이 a2, ..., ak와 같이 된다.
  2. 왼쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 a2, ..., ak, a1이 된다.
  3. 오른쪽으로 한 칸 이동시킨다. 이 연산을 수행하면, a1, ..., ak가 ak, a1, ..., ak-1이 된다.

큐에 처음에 포함되어 있던 수 N이 주어진다. 그리고 지민이가 뽑아내려고 하는 원소의 위치가 주어진다. (이 위치는 가장 처음 큐에서의 위치이다.) 이 때, 그 원소를 주어진 순서대로 뽑아내는데 드는 2번, 3번 연산의 최솟값을 출력하는 프로그램을 작성하시오.

입력

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

출력

첫째 줄에 문제의 정답을 출력한다.

예제 입력

10 3
1 2 3

예제 출력

0

힌트

출처

  • 문제를 번역한 사람: baekjoon
  • 문제의 오타를 찾은 사람: dhdh6190

알고리즘 분류

 

문제의 3가지 연산의 핵심은 1번 연산이다.

큐와 같이 맨 앞에 있는 요소를 뽑는 것이다.

뽑고 싶은 요소가 입력으로 주어졌을 때 맨 앞에 당연히 없게 주어지는 경우가 있다.

(첫번째 요소를 head라고 하고, 맨 끝의 요소를 tail이라고 명시하겠다)


이 때 2번이나 3번 연산을 통해 head를 왼쪽이나 오른쪽으로 이동시켜 해당 요소가 head에 온다면 그때 1번 연산을 수행하는 것이다.

결국 head에 뽑을 요소가 없다면 올 때까지 2번 3번 연산을 수행하여 head에 오게 하면 된다.

또 하나! 중요한 것은 2번, 3번 연산의 최솟값을 구하는 문제임으로 2번, 3번 연산 중 어떤 걸 수행할 지 잘 고려해야한다는 것이다.

무작정 2번이나 3번 연산을 수행한다면 최솟값이 아닐 경우가 발생하기 때문이다.


어떻게 2번, 3번 연산 중 최솟값을 구하기 위해 고려할 것인가?

뭐 이건 뻔하다. 다들 알 것이라 생각한다.

사실 이 문제는 문제만 제대로 이해한다면 쉽게 풀 수 있으니까 혹시나 틀렸던 사람이라면 분명 문제를 잘못 이해했을 것이다. 

아무튼 뽑을 요소의 위치를 기준으로 head쪽에 가까운지 tail쪽에 가까운지 계산하면 된다.

예를 들자면 아래와 같다.

int pos = list.indexOf(num); int size = list.size(); int left = pos; // head와의 거리 int right = size - pos - 1; // tail과의 거리

head와의 거리는 뽑을 요소의 인덱스라고 친다면, tail과의 거리는 크기 - head와의 거리 - 1이 된다.

별 거 없다. 그렇다. 계속 말하지만 문제만 정확히 이해한다면 쉽게 풀리는 문제다.

그리고 ArrayList를 사용하는 경우가 많다.

간단하게 핵심만 말하겠다.

ArrayList의 경우는 데이터 추가 삭제 시 임시배열을 이용하여 복사하게 된다. 

즉, 밀어내기식을 통해 처리되기 때문에 성능이 저하될 수 있다.

반면 LinkedList의 경우는 위치정보를 통해 처리됨으로 데이터 추가 삭제 시 용이하다.



★ Vector, ArrayList, LinkedList 차이 - http://seeit.kr/36

 

 

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;

public class Main4 {
 public static void main(String[] args) throws Exception {
  
  BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  
  String[] nm = br.readLine().split(" ");// 큐의 크기 N과 뽑아내려는 수의 개수 M
  String[] seq = br.readLine().split(" ");//뽑아내려는 수의 위치
  
  int N = Integer.parseInt(nm[0]);
  
  CircleQueue q = new CircleQueue(N, seq);
  
  System.out.println(q.getCount());
  
  br.close();

 }
}

class CircleQueue{
 private LinkedList<Integer> list = new LinkedList<Integer>();//빈번한 데이터의 추가,삭제가 이루어지는 List는 ArrayList보다 LinkedList가 적합
 private String[] seq;          //ArrayList는 검색할 때 더 적합
 private int count = 0;
 
 public CircleQueue(int size, String[] seq){
  for(int i = 1; i <= size; i++){
   list.add(i);
  }
  this.seq = seq;
  start();
 }
 
 private void start(){
  int length = seq.length;
  
  for(int i = 0; i < length; i++){
   int n = Integer.parseInt(seq[i]);
   operate(n);
  }
 }
 
 private void operate(int num){
 
  while(true){
   int pos = list.indexOf(num);
   int size = list.size();
   int left = pos;
   int right = size - pos - 1;
   if(left == 0){
    list.remove(pos);//1번 연산이 첫번째 원소 값만 추출하는 거기 때문에 값만 추출
    break;
   }
   
   if(left <= right){// 2번 연산 왼쪽으로 한 칸 이동
    list.addLast(list.removeFirst());
    ++count;
   }else{
    //3번 연산 오른쪽으로 한칸 이동
    list.addFirst(list.removeLast());
    ++count;
   }
  }
 }
 
 public int getCount() { return count; }

출처: http://mygumi.tistory.com/59

 

 

 

'알고리즘(Java) > ' 카테고리의 다른 글

백준 10866 덱  (0) 2017.11.28
백준 1158 조세퍼스 문제 0  (0) 2017.11.23
[자료구조]덱(Deque)  (0) 2017.11.23