diff --git "a/algorithm-study/src/main/java/week05/boj10866/\353\215\261_\352\271\200\354\236\254\355\233\210.java" "b/algorithm-study/src/main/java/week05/boj10866/\353\215\261_\352\271\200\354\236\254\355\233\210.java" new file mode 100644 index 0000000..5f246e8 --- /dev/null +++ "b/algorithm-study/src/main/java/week05/boj10866/\353\215\261_\352\271\200\354\236\254\355\233\210.java" @@ -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; + +/** + * 명령은 총 여덟 가지이다. + *

+ * push_front X: 정수 X를 덱의 앞에 넣는다. + * push_back X: 정수 X를 덱의 뒤에 넣는다. + * pop_front: 덱의 가장 앞에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. + * pop_back: 덱의 가장 뒤에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. + * size: 덱에 들어있는 정수의 개수를 출력한다. + * empty: 덱이 비어있으면 1을, 아니면 0을 출력한다. + * front: 덱의 가장 앞에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. + * back: 덱의 가장 뒤에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다. + *

+ * 첫째 줄에 명령의 수 N이 주어진다. (1 ≤ N ≤ 1,000,000) + * 둘째 줄부터 N개 줄에 명령이 하나씩 주어진다. + * 출력을 요구하는 명령은 하나 이상 주어진다. + *

+ * 메모리: 18356KB / 시간: 168ms + */ +public class 덱_김재훈 { + + static Deque 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; + } + } +} diff --git "a/algorithm-study/src/main/java/week05/boj13417/\354\271\264\353\223\234\353\254\270\354\236\220\354\227\264_\352\271\200\354\236\254\355\233\210.java" "b/algorithm-study/src/main/java/week05/boj13417/\354\271\264\353\223\234\353\254\270\354\236\220\354\227\264_\352\271\200\354\236\254\355\233\210.java" new file mode 100644 index 0000000..761b0ab --- /dev/null +++ "b/algorithm-study/src/main/java/week05/boj13417/\354\271\264\353\223\234\353\254\270\354\236\220\354\227\264_\352\271\200\354\236\254\355\233\210.java" @@ -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장의 카드가 일렬로 놓여있다. 각 카드에는 알파벳이 하나씩 적혀있다. + * 가장 왼쪽에 있는 카드부터 차례대로 한 장씩 가져올 수 있다. + * 그다음부터는 가져온 카드를 자신의 앞에 놓인 카드들의 가장 왼쪽, 또는 가장 오른쪽에 놓는다. + * 만들 수 있는 문자열 중 사전 순으로 가장 빠른 문자열 + *

+ * 첫째 줄에 테스트 케이스의 개수를 나타내는 자연수 T + * 각각의 테스트 케이스의 첫째 줄에 처음에 놓여있는 카드의 개수 N(1 ≤ N ≤ 1,000) + * 두 번째 줄에는 N장의 카드에 적힌 알파벳의 초기 순서 + *

+ * 수정 전 - 메모리: 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 cards = new ArrayDeque<>(); // 굳이 카드덱을 만들 필요가 없이, 문자를 읽는 순서대로 해결하면 된다. + Deque 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 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 cards, Deque 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()); + } + } +*/ +} diff --git a/algorithm-study/src/main/java/week05/boj20301/README.md b/algorithm-study/src/main/java/week05/boj20301/README.md new file mode 100644 index 0000000..de12044 --- /dev/null +++ b/algorithm-study/src/main/java/week05/boj20301/README.md @@ -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 + - 값이 하나만 남았기 때문에 루프를 돌지 않고 바로 결과값에 추가한다. diff --git "a/algorithm-study/src/main/java/week05/boj20301/\353\260\230\354\240\204\354\232\224\354\204\270\355\221\270\354\212\244_\352\271\200\354\236\254\355\233\210.java" "b/algorithm-study/src/main/java/week05/boj20301/\353\260\230\354\240\204\354\232\224\354\204\270\355\221\270\354\212\244_\352\271\200\354\236\254\355\233\210.java" new file mode 100644 index 0000000..4155f55 --- /dev/null +++ "b/algorithm-study/src/main/java/week05/boj20301/\353\260\230\354\240\204\354\232\224\354\204\270\355\221\270\354\212\244_\352\271\200\354\236\254\355\233\210.java" @@ -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> + *

+ * 이번주 반전 요세푸스 문제 + * M명의 사람이 제거될 때마다 원을 돌리는 방향을 바꾼다. + * (7, 3, 4)-반전 요세푸스 순열: <3, 6, 2, 7, 1, 5, 4> + *

+ * 반복문<-> 조건문 수정 전 - 메모리: 19460KB / 시간: 328ms + */ +public class 반전요세푸스_김재훈 { + + static Deque 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"); + } +} diff --git "a/algorithm-study/src/main/java/week05/boj2346/\355\222\215\354\204\240\355\204\260\353\234\250\353\246\254\352\270\260_\352\271\200\354\236\254\355\233\210.java" "b/algorithm-study/src/main/java/week05/boj2346/\355\222\215\354\204\240\355\204\260\353\234\250\353\246\254\352\270\260_\352\271\200\354\236\254\355\233\210.java" new file mode 100644 index 0000000..856c5bb --- /dev/null +++ "b/algorithm-study/src/main/java/week05/boj2346/\355\222\215\354\204\240\355\204\260\353\234\250\353\246\254\352\270\260_\352\271\200\354\236\254\355\233\210.java" @@ -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은 적혀있지 않다. + *

+ * 메모리: 17544KB / 시간: 188ms + */ +public class 풍선터뜨리기_김재훈 { + + static Deque ballon = new ArrayDeque<>(); + static Deque 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; + } +} diff --git "a/algorithm-study/src/main/java/week05/boj28279/\353\215\2612_\352\271\200\354\236\254\355\233\210.java" "b/algorithm-study/src/main/java/week05/boj28279/\353\215\2612_\352\271\200\354\236\254\355\233\210.java" new file mode 100644 index 0000000..8e3fa7f --- /dev/null +++ "b/algorithm-study/src/main/java/week05/boj28279/\353\215\2612_\352\271\200\354\236\254\355\233\210.java" @@ -0,0 +1,80 @@ +package week05.boj28279; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.StringTokenizer; + +/** + * 명령은 총 여덟 가지이다. + *

+ * 1 X: 정수 X를 덱의 앞에 넣는다. (1 ≤ X ≤ 100,000) + * 2 X: 정수 X를 덱의 뒤에 넣는다. (1 ≤ X ≤ 100,000) + * 3: 덱에 정수가 있다면 맨 앞의 정수를 빼고 출력한다. 없다면 -1을 대신 출력한다. + * 4: 덱에 정수가 있다면 맨 뒤의 정수를 빼고 출력한다. 없다면 -1을 대신 출력한다. + * 5: 덱에 들어있는 정수의 개수를 출력한다. + * 6: 덱이 비어있으면 1, 아니면 0을 출력한다. + * 7: 덱에 정수가 있다면 맨 앞의 정수를 출력한다. 없다면 -1을 대신 출력한다. + * 8: 덱에 정수가 있다면 맨 뒤의 정수를 출력한다. 없다면 -1을 대신 출력한다. + *

+ * 첫째 줄에 명령의 수 N이 주어진다. (1 ≤ N ≤ 1,000,000) + * 둘째 줄부터 N개 줄에 명령이 하나씩 주어진다. + * 출력을 요구하는 명령은 하나 이상 주어진다. + *

+ * 메모리: 259756KB / 시간: 1068ms + */ +public class 덱2_김재훈 { + + static Deque 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 + + 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 "1": + int inputFirst = Integer.parseInt(st.nextToken()); + deque.offerFirst(inputFirst); + break; + case "2": + int inputLast = Integer.parseInt(st.nextToken()); + deque.offerLast(inputLast); + break; + case "3": + sb.append(deque.isEmpty() ? "-1" : deque.pollFirst()).append("\n"); + break; + case "4": + sb.append(deque.isEmpty() ? "-1" : deque.pollLast()).append("\n"); + break; + case "5": + sb.append(deque.size()).append("\n"); + break; + case "6": + sb.append(deque.isEmpty() ? 1 : 0).append("\n"); + break; + case "7": + sb.append(deque.isEmpty() ? "-1" : deque.peekFirst()).append("\n"); + break; + case "8": + sb.append(deque.isEmpty() ? "-1" : deque.peekLast()).append("\n"); + break; + } + } +}