Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions algorithm-study/src/main/java/week05/boj10866/덱_김재훈.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package week05.boj10866;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;

/**
* 명령은 총 여덟 가지이다.
* <p>
* push_front X: 정수 X를 덱의 앞에 넣는다.
* push_back X: 정수 X를 덱의 뒤에 넣는다.
* pop_front: 덱의 가장 앞에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
* pop_back: 덱의 가장 뒤에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
* size: 덱에 들어있는 정수의 개수를 출력한다.
* empty: 덱이 비어있으면 1을, 아니면 0을 출력한다.
* front: 덱의 가장 앞에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
* back: 덱의 가장 뒤에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
* <p>
* 첫째 줄에 명령의 수 N이 주어진다. (1 ≤ N ≤ 1,000,000)
* 둘째 줄부터 N개 줄에 명령이 하나씩 주어진다.
* 출력을 요구하는 명령은 하나 이상 주어진다.
* <p>
* 메모리: 18356KB / 시간: 168ms
*/
public class 덱_김재훈 {

static Deque<Integer> deque = new ArrayDeque<>();
static StringBuilder sb = new StringBuilder();

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int n = Integer.parseInt(st.nextToken());

while (n-- > 0) {
solution(br);
}

System.out.println(sb);
}

private static void solution(BufferedReader br) throws IOException {
StringTokenizer st;
st = new StringTokenizer(br.readLine());
String command = st.nextToken();

switch (command) {
case "push_front":
deque.offerFirst(Integer.parseInt(st.nextToken()));
break;

case "push_back":
deque.offerLast(Integer.parseInt(st.nextToken()));
break;

case "pop_front":
sb.append(deque.isEmpty() ? -1 : deque.pollFirst()).append("\n");
break;

case "pop_back":
sb.append(deque.isEmpty() ? -1 : deque.pollLast()).append("\n");
break;

case "size":
sb.append(deque.size()).append("\n");
break;

case "empty":
sb.append(deque.isEmpty() ? 1 : 0).append("\n");
break;

case "front":
sb.append(deque.isEmpty() ? -1 : deque.peekFirst()).append("\n");
break;

case "back":
sb.append(deque.isEmpty() ? -1 : deque.peekLast()).append("\n");
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package week05.boj13417;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;

/**
* N장의 카드가 일렬로 놓여있다. 각 카드에는 알파벳이 하나씩 적혀있다.
* 가장 왼쪽에 있는 카드부터 차례대로 한 장씩 가져올 수 있다.
* 그다음부터는 가져온 카드를 자신의 앞에 놓인 카드들의 가장 왼쪽, 또는 가장 오른쪽에 놓는다.
* 만들 수 있는 문자열 중 사전 순으로 가장 빠른 문자열
* <p>
* 첫째 줄에 테스트 케이스의 개수를 나타내는 자연수 T
* 각각의 테스트 케이스의 첫째 줄에 처음에 놓여있는 카드의 개수 N(1 ≤ N ≤ 1,000)
* 두 번째 줄에는 N장의 카드에 적힌 알파벳의 초기 순서
* <p>
* 수정 전 - 메모리: 29584KB / 시간: 304ms
* 수정 후 - 메모리: 28820KB / 시간: 284ms
*/
public class 카드문자열_김재훈 {

static StringBuilder sb = new StringBuilder();

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int t = Integer.parseInt(st.nextToken()); // 테스트 케이스의 개수 T

while (t-- > 0) { // 테스트 케이스 개수만큼 반복
// Deque<String> cards = new ArrayDeque<>(); // 굳이 카드덱을 만들 필요가 없이, 문자를 읽는 순서대로 해결하면 된다.
Deque<String> result = new ArrayDeque<>();

int n = Integer.parseInt(br.readLine()); // 카드의 개수 N
st = new StringTokenizer(br.readLine());

while (n-- > 0) { // 카드의 개수만큼 반복
solution(st, result);
}

result.forEach(sb::append);

if (t != 0) {
sb.append("\n");
}
}
System.out.println(sb);
}

private static void solution(StringTokenizer st, Deque<String> result) {
String card = st.nextToken();

if (result.isEmpty()) { // result가 비었을 경우 우선 하나를 먼저 넣어준다.
result.offer(card);
return;
}

if (result.peekFirst().compareTo(card) >= 0) { // 양수(또는 0)인 경우 result 알파벳이 큰(같은) 것이므로 왼쪽(앞쪽) 배치
result.offerFirst(card);
} else { // 음수인 경우 result 알파벳이 작은 것이므로 오른쪽(뒤쪽) 배치
result.offerLast(card);
}
}

/*
private static void solution(Deque<String> cards, Deque<String> result) {
if (result.isEmpty()) { // result가 비었을 경우 우선 하나를 먼저 넣어준다.
result.offer(cards.pollFirst());
return;
}

String dequeFirst = cards.peekFirst();
String resultFirst = result.peekFirst();
int compared = resultFirst.compareTo(dequeFirst);
// 양수(또는 0)일 경우 result 쪽 알파벳이 큰(또는 같은) 것이므로 왼쪽(앞쪽)으로 배치
// 음수일 경우 result 쪽 알파벳이 작은 것이므로 오른쪽(뒤쪽)으로 배치

if (compared >= 0) {
result.offerFirst(cards.pollFirst());
} else {
result.offerLast(cards.pollFirst());
}
}
*/
}
55 changes: 55 additions & 0 deletions algorithm-study/src/main/java/week05/boj20301/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# 문제
- 지난주 풀었던 요세푸스 문제
- 원을 이루며 앉아있는 N명의 사람이 있다.
- K번 사람을 제거 후 오른쪽으로 K번째 사람을 계속해서 제거해 나간다.
- 모든 사람이 제거되었을 때 제거된 사람의 순서를 구한다.
- (7, 3)-요세푸스 순열: <3, 6, 2, 7, 5, 1, 4>

- 이번주 풀 반전 요세푸스 문제
- 한 방향으로만 돌아가는 것은 지루하다.
- M명의 사람이 제거될 때마다 원을 돌리는 방향을 계속해서 바꾼다.
- (7, 3, 4)-반전 요세푸스 순열: <3, 6, 2, 7, 1, 5, 4>
---
# 추측
- 요세푸스 문제는 원을 대신해 일자로 줄을 세워 가장 앞 사람을 가장 뒤로 보내며 반복했다.
- 반전 요세푸스 문제의 경우 M명의 사람을 제거할 때마다 방향을 바꾼다.
- 여러 번 반복될 수도 있으므로 변수를 하나 지정해 배수로 판별한다.
- 방향이 바뀔 때, 반대로 가장 뒤에 있는 사람을 가장 앞으로 보내면 될 것이다.
- boolean 값으로 판별해 방향을 판단한다.
- 방향이 바뀌었다면 선택하는 사람의 위치도 바뀌어야 할 것이다.
- 정방향으로 가던 중이라면 가장 앞 사람, 역방향으로 바뀌었다면 가장 뒷 사람을 선택한다.
---
# 풀이
- 예) (7, 3, 4)-반전 요세푸스 순열
- round1 - 가장 앞 사람 선택
- loop1. {1, 2, 3, 4, 5, 6, 7} -> {2, 3, 4, 5, 6, 7, 1} / 결과 {}
- loop2. {2, 3, 4, 5, 6, 7, 1} -> {3, 4, 5, 6, 7, 1, 2} / 결과 {}
- loop3. {3, 4, 5, 6, 7, 1, 2} -> {4, 5, 6, 7, 1, 2} / 결과 {3}

- round2 - 가장 앞 사람 선택
- loop1. {4, 5, 6, 7, 1, 2} -> {5, 6, 7, 1, 2, 4} / 결과 {3}
- loop2. {5, 6, 7, 1, 2, 4} -> {6, 7, 1, 2, 4, 5} / 결과 {3}
- loop3. {6, 7, 1, 2, 4, 5} -> {7, 1, 2, 4, 5} / 결과 {3, 6}

- round3 - 가장 앞 사람 선택
- loop1. {7, 1, 2, 4, 5} -> {1, 2, 4, 5, 7} / 결과 {3, 6}
- loop2. {1, 2, 4, 5, 7} -> {2, 4, 5, 7, 1} / 결과 {3, 6}
- loop3. {2, 4, 5, 7, 1} -> {4, 5, 7, 1} / 결과 {3, 6, 2}

- round4 - 가장 앞 사람 선택
- loop1. {4, 5, 7, 1} -> {5, 7, 1, 4} / 결과 {3, 6, 2}
- loop2. {5, 7, 1, 4} -> {7, 1, 4, 5} / 결과 {3, 6, 2}
- loop3. {7, 1, 4, 5} -> {1, 4, 5} / 결과 {3, 6, 2, 7}

- round5 - 방향 전환, 가장 뒷 사람 선택
- loop1. {1, 4, 5} -> {5, 1, 4} / 결과 {3, 6, 2, 7}
- loop2. {5, 1, 4} -> {4, 5, 1} / 결과 {3, 6, 2, 7}
- loop3. {4, 5, 1} -> {4, 5} / 결과 {3, 6, 2, 7, 1}

- round6 - 가장 뒷 사람 선택
- loop1. {4, 5} -> {5, 4} / 결과 {3, 6, 2, 7, 5}
- loop2. {5, 4} -> {4, 5} / 결과 {3, 6, 2, 7, 5}
- loop3. {4, 5} -> {4} / 결과 {3, 6, 2, 7, 5, 5}

- round7
- 값이 하나만 남았기 때문에 루프를 돌지 않고 바로 결과값에 추가한다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package week05.boj20301;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;

/**
* 지난주 풀었던 기존 요세푸스 문제
* 원을 이룬 N명의 사람들
* K번 사람 제거 후 오른쪽의 K번째 사람 계속해서 제거
* (7, 3)-요세푸스 순열: <3, 6, 2, 7, 5, 1, 4>
* <p>
* 이번주 반전 요세푸스 문제
* M명의 사람이 제거될 때마다 원을 돌리는 방향을 바꾼다.
* (7, 3, 4)-반전 요세푸스 순열: <3, 6, 2, 7, 1, 5, 4>
* <p>
* 반복문<-> 조건문 수정 전 - 메모리: 19460KB / 시간: 328ms
*/
public class 반전요세푸스_김재훈 {

static Deque<Integer> deque = new ArrayDeque<>();
static StringBuilder sb = new StringBuilder();

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int n = Integer.parseInt(st.nextToken()); // 총 N명의 사람
int k = Integer.parseInt(st.nextToken()); // 계속해서 제거할 K번째 사람
int m = Integer.parseInt(st.nextToken()); // 방향을 바꾸는 기준이 되는 M명의 사람
int count = 0; // 반복문 내에서 M을 판별하기 위한 변수
boolean flag = true; // 방향을 바꿔주기 위한 flag, true = 정방향, false = 역방향

initDeque(n); // N명의 사람 번호 순서대로 나열

while (!deque.isEmpty()) {
if (flag) {
repeatForward(k); // 정방향 반복
} else {
repeatReverse(k); // 역방향 반복
}

/*
// 반복문 내에서 조건문 도는 것보다 조건문 내에서 반복문 도는 것이 빠르다.
for (int i = 0; i < k - 1; i++) {
if (flag) {
deque.offerLast(deque.pollFirst()); // 정방향, 앞 사람을 뒤로 보내기
} else {
deque.offerFirst(deque.pollLast()); // 역방향, 뒷 사람을 앞으로 보내기
}
}
*/

count++; // 한 명을 추가할 때마다 1씩 증가한다.

if (count % m == 0) { // 나눴을 때 0이 되면 M의 배수
flag = !flag;
}
}
System.out.println(sb);
}

private static void initDeque(int n) {
for (int i = 1; i <= n; i++) {
deque.offer(i);
}
}

private static void repeatForward(int k) {
for (int i = 0; i < k - 1; i++) {
deque.offerLast(deque.pollFirst()); // 정방향, 앞 사람을 뒤로 보내기
}
sb.append(deque.pollFirst()).append("\n");
}

private static void repeatReverse(int k) {
for (int i = 0; i < k - 1; i++) {
deque.offerFirst(deque.pollLast()); // 역방향, 뒷 사람을 앞으로 보내기
}
sb.append(deque.pollLast()).append("\n");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package week05.boj2346;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.StringTokenizer;

/**
* i번 풍선의 오른쪽에는 i+1번 풍선이 있고, 왼쪽에는 i-1번 풍선이 있다.
* 풍선 안에 있는 종이를 꺼내어 그 종이에 적혀있는 값만큼 이동하여 다음 풍선을 터뜨린다.
* 양수가 적혀 있을 경우에는 오른쪽으로, 음수가 적혀 있을 때는 왼쪽으로 이동한다.
* 이미 터진 풍선은 빼고 이동한다.
* 첫째 줄에 자연수 N(1 ≤ N ≤ 1,000)이 주어진다.
* 다음 줄에는 차례로 각 풍선 안의 종이에 적혀 있는 수가 주어진다. 종이에 0은 적혀있지 않다.
* <p>
* 메모리: 17544KB / 시간: 188ms
*/
public class 풍선터뜨리기_김재훈 {

static Deque<Integer> ballon = new ArrayDeque<>();
static Deque<Integer> number = new ArrayDeque<>();
static StringBuilder sb = new StringBuilder();

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());

int n = Integer.parseInt(st.nextToken()); // n개의 풍선

initBallon(br, n);

while (!ballon.isEmpty()) {
if (solution()) break;
}

System.out.println(sb);
}

private static void initBallon(BufferedReader br, int n) throws IOException {
StringTokenizer st;
st = new StringTokenizer(br.readLine());
for (int i = 1; i <= n; i++) {
ballon.offer(i); // 1부터 n까지 순서대로 풍선 놓기
number.offer(Integer.parseInt(st.nextToken())); // 풍선에 적힌 번호 순서대로 나열
}
}

private static boolean solution() {
if (ballon.size() == 1) { // 풍선이 1개만 남으면 반복할 필요 없이 바로 반환하면 된다.
sb.append(ballon.poll());
return true;
}

Integer peekFirst = number.peekFirst();

if (peekFirst > 0) { // 확인한 수가 양수일 경우
sb.append(ballon.pollFirst()).append(" ");
Integer positive = number.pollFirst();

for (int i = 0; i < positive - 1; i++) { // k-1 만큼 반복하며
ballon.offerLast(ballon.pollFirst()); // 가장 앞의 수를 가장 뒤로 보낸다.
number.offerLast(number.pollFirst()); // 풍선을 옮길 때 번호도 함께 옮긴다.
}
// else if 가 아닌 if로 실행 시 오류 발생!
} else if (peekFirst < 0) { // 확인한 수가 음수일 경우
sb.append(ballon.pollFirst()).append(" ");
int negative = Math.abs(number.pollFirst()); // 음수이므로 절대값으로 바꿔준다.

for (int i = 0; i < negative; i++) { // k 만큼 반복하며
ballon.offerFirst(ballon.pollLast()); // 가장 뒤의 수를 가장 앞으로 보낸다.
number.offerFirst(number.pollLast()); // 풍선을 옮길 때 번호도 함께 옮긴다.
}
}
return false;
}
}
Loading