diff --git "a/BOJ/[1536] \352\260\234\352\267\274\354\203\201/asever0318/Main_1563.java" "b/BOJ/[1536] \352\260\234\352\267\274\354\203\201/asever0318/Main_1563.java" new file mode 100644 index 00000000..2a072c60 --- /dev/null +++ "b/BOJ/[1536] \352\260\234\352\267\274\354\203\201/asever0318/Main_1563.java" @@ -0,0 +1,40 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Main { + static int N; + static final int D = 1000000; + static int[][][] attend; + + public static void main(String[] args) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + N = Integer.parseInt(br.readLine()); + attend = new int[N+1][2][3]; // [일][지각][결석] + + attendance(); + System.out.println((attend[N][0][0] + attend[N][0][1] + attend[N][0][2] + attend[N][1][0] + attend[N][1][1] + attend[N][1][2]) % D); + } + + static void attendance(){ + + attend[1][0][0] = 1; + attend[1][0][1] = 1; + attend[1][1][0] = 1; + + for(int i = 2; i <= N; i++){ + // 1. i일까지 지각을 안한 경우 + // i번째 날에 지각 0, 결석 0일일 경우 + attend[i][0][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2]) % D; + attend[i][0][1] = attend[i-1][0][0] % D; // i번째 날에 결석을 연속 1번 하려면 전날에는 결석을 했으면 안됨 + attend[i][0][2] = attend[i-1][0][1] % D; // i번째 날에 결석을 연속 2번 하려면 전날에 결석을 연속 1번 했어야 함 + + // 2. i일까지 지각을 1번 한 경우 + attend[i][1][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2] + attend[i-1][1][0] + attend[i-1][1][1] + attend[i-1][1][2]) % D; + attend[i][1][1] = attend[i-1][1][0] % D; // 지각과 결석을 동시에 못함주의 -> 결석만 고려 + attend[i][1][2] = attend[i-1][1][1] % D; + } + } +} +// 개근상 받을 수 없는 사람 : 1. 지각 2번 이상, 2. 결석 연속 세 번이상 +// result => 개근상을 받을 수 있는 출결정보의 개수 diff --git "a/BOJ/[1536] \352\260\234\352\267\274\354\203\201/asever0318/README.md" "b/BOJ/[1536] \352\260\234\352\267\274\354\203\201/asever0318/README.md" new file mode 100644 index 00000000..8f24ed19 --- /dev/null +++ "b/BOJ/[1536] \352\260\234\352\267\274\354\203\201/asever0318/README.md" @@ -0,0 +1,35 @@ +# [1563] 개근상 + +## :pushpin: **Algorithm** + +DP + +## :round_pushpin: **Logic** +```java +static void attendance(){ + + attend[1][0][0] = 1; + attend[1][0][1] = 1; + attend[1][1][0] = 1; + + for(int i = 2; i <= N; i++){ + // 1. i일까지 지각을 안한 경우 + // i번째 날에 지각 0, 결석 0일일 경우 + attend[i][0][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2]) % D; + attend[i][0][1] = attend[i-1][0][0] % D; // i번째 날에 결석을 연속 1번 하려면 전날에는 결석을 했으면 안됨 + attend[i][0][2] = attend[i-1][0][1] % D; // i번째 날에 결석을 연속 2번 하려면 전날에 결석을 연속 1번 했어야 함 + + // 2. i일까지 지각을 1번 한 경우 + attend[i][1][0] = (attend[i-1][0][0] + attend[i-1][0][1] + attend[i-1][0][2] + attend[i-1][1][0] + attend[i-1][1][1] + attend[i-1][1][2]) % D; + attend[i][1][1] = attend[i-1][1][0] % D; // 지각과 결석을 동시에 못함주의 -> 결석만 고려 + attend[i][1][2] = attend[i-1][1][1] % D; + } +} +``` +- 일, 지각, 결석 세 가지를 고려해야 되기 때문에 3차원 배열로 선언해주었다. +- 지각을 기준으로 i일까지 지각을 안한 경우 / i일까지 지각을 1번한 경우로 나누어 각 경우의 수 6가지를 저장해준다. + +## :black_nib: **Review** +- 경우의 수 구해서 풀려고 했는데 DP문제였다. 슬프다. 어렵다. +- 3차원 DP는 오랜만에 풀어봤다. 다음엔 반드시.. +- 근데 마지막 N번째 값을 모두 더 할 때 처음에 함수로 빼서 작성했는데 계속 틀려서 함수를 없애고 print문에 바로 더해서 구했더니 통과했다 왜지..! 더 알아봐야겠다.. \ No newline at end of file diff --git "a/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/asever0318/Main_15565.java" "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/asever0318/Main_15565.java" new file mode 100644 index 00000000..118edd2f --- /dev/null +++ "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/asever0318/Main_15565.java" @@ -0,0 +1,76 @@ +package BOJ; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; + +public class Main_15565 { + static int N, K; + static int[] doll; + + public static void main(String[] args) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + String[] str = br.readLine().split(" "); + N = Integer.parseInt(str[0]); + K = Integer.parseInt(str[1]); + + StringTokenizer st = new StringTokenizer(br.readLine()); + doll = new int[N]; + + int i = 0; + while(st.hasMoreTokens()) { + doll[i] = Integer.parseInt(st.nextToken()); + i++; + } + + System.out.println(getRyanCount()); + } + + static int getRyanCount() { + int count = 0; + int ryan = 0; + int min = Integer.MAX_VALUE; + int left = 0; + int right = 0; + + // 첫 요소가 2라면 처음 1이 나오는 위치까지 이동 + if(doll[right] == 2) { + while(true) { + right++; + if(right >= N || doll[right] == 1) { + left = right; + break; + } + } + } + + // 1이 나오는 위치부터 진행 + while(left < N && right < N) { + count++; + if(doll[right] == 1) { // 만약 1을 만나면 라이언 추가 + ryan++; + + if(ryan == K) { // 만약 라이언이 K개만큼 포함되어 있다면 + min = Math.min(min, count); // min값 갱신 후 + + while(true) { // left좌표를 다음 1이 나오는 위치로 옮겨주기 + left++; + count--; // 이동하는 만큼 count에서도 제거 + if(left >= N || doll[left] == 1) { + break; + } + } + ryan--; // 다음 좌표로 옮겼기 때문에 라이언 수는 -1 + } + } + right++; + } + + if(min == Integer.MAX_VALUE) { // min값에 변화가 없으면 K개 이상의 연속된 집합을 못찾은 것 + min = -1; + } + + return min; + } +} diff --git "a/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/asever0318/README.md" "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/asever0318/README.md" new file mode 100644 index 00000000..4f53f7c2 --- /dev/null +++ "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/asever0318/README.md" @@ -0,0 +1,56 @@ +# [15565] 귀여운 라이언 + +## :pushpin: **Algorithm** + +투포인터 + +## :round_pushpin: **Logic** +```java +static int getRyanCount() { + [...] + + // 첫 요소가 2라면 처음 1이 나오는 위치까지 이동 + if(doll[right] == 2) { + while(true) { + right++; + if(right >= N || doll[right] == 1) { + left = right; + break; + } + } + } + + // 1이 나오는 위치부터 진행 + while(left < N && right < N) { + count++; + if(doll[right] == 1) { // 만약 1을 만나면 라이언 추가 + ryan++; + + if(ryan == K) { // 만약 라이언이 K개만큼 포함되어 있다면 + min = Math.min(min, count); // min값 갱신 후 + + while(true) { // left좌표를 다음 1이 나오는 위치로 옮겨주기 + left++; + count--; // 이동하는 만큼 count에서도 제거 + if(left >= N || doll[left] == 1) { + break; + } + } + ryan--; // 다음 좌표로 옮겼기 때문에 라이언 수는 -1 + } + } + right++; + } + + if(min == Integer.MAX_VALUE) { // min값에 변화가 없으면 K개 이상의 연속된 집합을 못찾은 것 + min = -1; + } + + return min; +} +``` +- 최소 길이를 찾는 것이기 때문에 가장 처음 1이 나오는 위치까지 먼저 이동 후 진행한다. +- 라이언의 개수가 K개가 되면 min값을 갱신하고 left 좌표를 다음 라이언이 있는 곳으로 이동 시킨 후 반복한다. + +## :black_nib: **Review** +- 문제를 보고 바로 투포인터로 풀어야겠다고 생각이 들었다. 생각보다 빨리 풀 수 있었다. 쉬운 문제지만 투포인터 문제에 익숙해진 거 같아서 기분이 좋다! \ No newline at end of file diff --git "a/BOJ/[3584] \352\260\200\354\236\245 \352\260\200\352\271\214\354\232\264 \352\263\265\355\206\265 \354\241\260\354\203\201/asever0318/Main_3584.java" "b/BOJ/[3584] \352\260\200\354\236\245 \352\260\200\352\271\214\354\232\264 \352\263\265\355\206\265 \354\241\260\354\203\201/asever0318/Main_3584.java" new file mode 100644 index 00000000..a8415279 --- /dev/null +++ "b/BOJ/[3584] \352\260\200\354\236\245 \352\260\200\352\271\214\354\232\264 \352\263\265\355\206\265 \354\241\260\354\203\201/asever0318/Main_3584.java" @@ -0,0 +1,72 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.*; + +public class Main { + static int N; + static int[] parent; + static Stack p1, p2; + + public static void main(String[] args) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + + int T = Integer.parseInt(br.readLine()); + for(int t = 0; t < T; t++) { + parent = new int[10001]; + + N = Integer.parseInt(br.readLine()); + + for(int i = 0; i < N-1; i++){ + String[] temp = br.readLine().split(" "); + parent[Integer.parseInt(temp[1])] = Integer.parseInt(temp[0]); + } + + String[] temp2 = br.readLine().split(" "); + int num1 = Integer.parseInt(temp2[0]); + p1 = new Stack<>(); + int num2 = Integer.parseInt(temp2[1]); + p2 = new Stack<>(); + + // 부모를 거슬러가면서 스택에 넣기 + int index = num1; + p1.push(index); + while(parent[index] != 0){ + p1.push(parent[index]); + index = parent[index]; + } + + index = num2; + p2.push(index); + while(parent[index] != 0){ + p2.push(parent[index]); + index = parent[index]; + } + + System.out.println(getAncestor(num1, num2)); + } + } + + static int getAncestor(int n1, int n2){ + int answer = 0; + + // 두 스택에서 하나씩 빼면서 같은 수가 나오면 공통 조상 + // --> 마지막에 나오는 공통 조상이 제일 가까운 공통 조상 + + while(!p1.isEmpty() && !p2.isEmpty()){ // 둘 중 하나가 빌 때까지 + int num1 = p1.pop(); + int num2 = p2.pop(); + + if(num1 != num2){ // 부모가 다르면 멈춤 + break; + } + + answer = num1; + } + + return answer; + } +} + +// 가장 가까운 공통 조상 찾기 + diff --git "a/BOJ/[3584] \352\260\200\354\236\245 \352\260\200\352\271\214\354\232\264 \352\263\265\355\206\265 \354\241\260\354\203\201/asever0318/README.md" "b/BOJ/[3584] \352\260\200\354\236\245 \352\260\200\352\271\214\354\232\264 \352\263\265\355\206\265 \354\241\260\354\203\201/asever0318/README.md" new file mode 100644 index 00000000..1d92def6 --- /dev/null +++ "b/BOJ/[3584] \352\260\200\354\236\245 \352\260\200\352\271\214\354\232\264 \352\263\265\355\206\265 \354\241\260\354\203\201/asever0318/README.md" @@ -0,0 +1,37 @@ +# [3584] 가장 가까운 공통 조상 + +## :pushpin: **Algorithm** + +스택, 트리 + +## :round_pushpin: **Logic** +- parent라는 int배열에 해당 인덱스 숫자의 부모를 저장한다. +- 공통 조상을 찾아야하는 두 숫자 각 stack을 만들어서 부모를 root까지 쭉 push한다. + +```java +static int getAncestor(int n1, int n2){ + int answer = 0; + + // 두 스택에서 하나씩 빼면서 같은 수가 나오면 공통 조상 + // --> 마지막에 나오는 공통 조상이 제일 가까운 공통 조상 + + while(!p1.isEmpty() && !p2.isEmpty()){ // 둘 중 하나가 빌 때까지 + int num1 = p1.pop(); + int num2 = p2.pop(); + + if(num1 != num2){ // 부모가 다르면 멈춤 + break; + } + + answer = num1; + } + + return answer; +} +``` +- 두 스택에서 하나씩 빼면서 비교 후 두 숫자가 같으면 공통 조상이므로 answer에 저장하고, 두 수가 같지 않을 때까지 반복한다. + +## :black_nib: **Review** +- 처음에는 트리를 리스트로 구현하려고 했는데 어떤 숫자에 자식이 있는지 알 수 없기 때문에 리스트를 미리 만들어 두는 것은 비효율적이라 생각해서 다른 방법을 생각하다가 조상을 찾는 것이기 때문에 부모만 저장해두고 타고타고 올라가면 된다는 생각이 들어 parent 배열을 만들었다. +- 부모를 저장하는 parent배열은 만들었는데 막상 끝에서부터 부모를 비교하면서 올라가려니 부모의 depth가 다를 수 있다는 생각이 들었다. 어떻게 해결할 지 고민하다가 결국 다른 사람의 답을 참고했다. +- stack에 넣어두면 가장 위에 있는 root가 top에 오기 때문에 같은 depth끼리 비교할 수 있게 된다. 사람들은 정말 똑똑하다.... \ No newline at end of file diff --git "a/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/asever0318/README.md" "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/asever0318/README.md" new file mode 100644 index 00000000..8f06504f --- /dev/null +++ "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/asever0318/README.md" @@ -0,0 +1,40 @@ +# [155651] 호텔 대실 + +## :pushpin: **Algorithm** + +누적합 + +## :round_pushpin: **Logic** +```java +public int solution(String[][] book_time) { + room = new int[24*60+10]; // 24시간*60분+10분 -> 가장 늦게 끝나는 시간 + + for(int i = 0; i < book_time.length; i++){ + int start = getMinutes(book_time[i][0]); + int end = getMinutes(book_time[i][1]); + + room[start] += 1; // 시작 시간에는 1 저장 + room[end + 10] += -1; // 끝나는 시간 + 청소시간 10분에는 -1 저장 + } + + prefixSum(); // 누적합 + + return max; +} +``` +- 최대 크기의 1차원 배열을 하나 생성한다. +- 시작 위치에 1을 추가하고 끝 위치에 -1을 추가한다. + +```java +static void prefixSum(){ + for(int i = 1; i < 24*60+10; i++){ + room[i] += room[i-1]; // 이전 값을 더하기 + max = Math.max(max, room[i]); // 최대값 갱신(방의 수) + } +} +``` +- 앞에서부터 뒤로 진행하면서 이전 요소의 값을 더한다. +- 누적합 배열에서 최대값이 필요한 최소의 방의 수가 된다. + +## :black_nib: **Review** +- 처음에 우선순위큐로 풀다가 누적합 풀이를 발견해서 누적합으로 풀어봤는데.. 시작을 1, 끝을 -1로 해서 누적합으로 카운트하다니 사람들은 정말 천재다. 좋은 풀이법을 배운 것 같다. \ No newline at end of file diff --git "a/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/asever0318/Solution_155651.java" "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/asever0318/Solution_155651.java" new file mode 100644 index 00000000..53402b73 --- /dev/null +++ "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/asever0318/Solution_155651.java" @@ -0,0 +1,41 @@ +class Solution { + static int[] room; // 배열에 저장된 최대값이 최소 필요한 방의 수 + static int max; + + public int solution(String[][] book_time) { + room = new int[24*60+10]; // 24시간*60분+10분 -> 가장 늦게 끝나는 시간 + + for(int i = 0; i < book_time.length; i++){ + int start = getMinutes(book_time[i][0]); + int end = getMinutes(book_time[i][1]); + + room[start] += 1; // 시작 시간에는 1 저장 + room[end + 10] += -1; // 끝나는 시간 + 청소시간 10분에는 -1 저장 + } + + prefixSum(); // 누적합 + + return max; + } + + static int getMinutes(String time){ + int total = 0; + String[] temp = time.split(":"); + + total = Integer.parseInt(temp[0])*60; + total += Integer.parseInt(temp[1]); + + return total; + } + + static void prefixSum(){ + for(int i = 1; i < 24*60+10; i++){ + room[i] += room[i-1]; // 이전 값을 더하기 + max = Math.max(max, room[i]); // 최대값 갱신(방의 수) + } + } +} + +// 누적합 방법 +// 1. 시작 위치에 1을 추가하고 끝위치에-1을 추가한다. +// 2. 앞에서부터 뒤로 진행하면서 이전의 값을 더한다. \ No newline at end of file diff --git "a/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/asever0318/README.md" "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/asever0318/README.md" new file mode 100644 index 00000000..305e4cfb --- /dev/null +++ "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/asever0318/README.md" @@ -0,0 +1,41 @@ +# [68646] 풍선 터트리기 + +## :pushpin: **Algorithm** + +구현 + +## :round_pushpin: **Logic** +```java +for(int i = 1; i < size-1; i++){ // i원소의 왼쪽에 있는 값들 중 최소값을 저장 + if(leftMin > a[i]){ + leftMin = a[i]; + } + left[i] = leftMin; +} + +for(int i = size-2; i > 0; i--){ // (오른쪽에서부터) i원소의 오른쪽에 있는 값들 중 최소값을 저장 + if(rightMin > a[i]){ // 만약 더 작은 수면 최소값 갱신 + rightMin = a[i]; + } + right[i] = rightMin; // 최소값 저장 +} +``` +- i번째 요소를 기준으로 왼쪽/오른쪽에 있는 값들 중 최소값을 배열에 저장한다. + +```java +static int getBalloonCount(int[] a){ + int count = 2; // 가장 왼, 오른쪽은 무조건 남을 수 있다(마지막에 사용하면) + + for(int i = 1; i < size-1; i++){ + if(a[i] <= left[i] || a[i] <= right[i]){ // 하나라도 나보다 같거나 크면, 그 수가 삭제되기 때문에 나는 남을 수 있음 + count++; + } + } + + return count; +} +``` +- 어떤 요소가 마지막에 남으려면 가장 마지막에 작은 수를 제거하는 1번을 사용해야하는데, i번째 요소를 남기려고 했을 때 해당 요소 양쪽에 둘 다 작은 값이 오면 i번째 요소가 제거되므로 양쪽 중 하나라도 해당 요소와 같거나 크면 남을 수 있게 된다. + +## :black_nib: **Review** +- 정말 오래 고민했는데 도저히 생각나지 않아서 다른 사람의 답을 참고했다. 한 요소가 마지막까지 남기 위해서는 가장 마지막에 작은 수 제거를 사용해야 된다는 점을 생각해내지 못해서 풀지 못했던 것 같다. \ No newline at end of file diff --git "a/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/asever0318/Solution_68646.java" "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/asever0318/Solution_68646.java" new file mode 100644 index 00000000..4ccab4e7 --- /dev/null +++ "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/asever0318/Solution_68646.java" @@ -0,0 +1,47 @@ +import java.util.*; + +class Solution { + static int[] left, right; + static int leftMin, rightMin, size; + + public int solution(int[] a) { + + size = a.length; + left = new int[size]; // 각 인덱스 기준 왼쪽 최소값 저장 + right = new int[size]; // 각 인덱스 기준 오른쪽 최소값 저장 + leftMin = a[0]; // 왼쪽 최소값 초기화 + rightMin = a[size-1]; // 오른쪽 최소값 초기화 + + for(int i = 1; i < size-1; i++){ // i원소의 왼쪽에 있는 값들 중 최소값을 저장 + if(leftMin > a[i]){ + leftMin = a[i]; + } + left[i] = leftMin; + } + + for(int i = size-2; i > 0; i--){ // (오른쪽에서부터) i원소의 오른쪽에 있는 값들 중 최소값을 저장 + if(rightMin > a[i]){ // 만약 더 작은 수면 최소값 갱신 + rightMin = a[i]; + } + right[i] = rightMin; // 최소값 저장 + } + + if(size == 1){ // 원소가 1개면 무조건 남음 + return 1; + } + + return getBalloonCount(a); + } + + static int getBalloonCount(int[] a){ + int count = 2; // 가장 왼, 오른쪽은 무조건 남을 수 있다(마지막에 사용하면) + + for(int i = 1; i < size-1; i++){ + if(a[i] <= left[i] || a[i] <= right[i]){ // 하나라도 나보다 같거나 크면, 그 수가 삭제되기 때문에 나는 남을 수 있음 + count++; + } + } + + return count; + } +} \ No newline at end of file