From efcd8a00b2fab1ae5435d74c7527ff655140b21a Mon Sep 17 00:00:00 2001 From: ksg2388 Date: Wed, 12 Jul 2023 10:11:32 +0900 Subject: [PATCH 1/5] =?UTF-8?q?19week=20:=20BOJ[15565]=20=EA=B7=80?= =?UTF-8?q?=EC=97=AC=EC=9A=B4=20=EB=9D=BC=EC=9D=B4=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ksg2388/Main.js" | 58 +++++++++++++++++++ .../ksg2388/README.md" | 46 +++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 "BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/Main.js" create mode 100644 "BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/README.md" diff --git "a/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/Main.js" "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/Main.js" new file mode 100644 index 00000000..2f6ab8d0 --- /dev/null +++ "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/Main.js" @@ -0,0 +1,58 @@ +const fs = require('fs'); +const filePath = process.platform === 'linux' ? '/dev/stdin' : 'input.txt'; +let input = fs.readFileSync(filePath).toString().trim().split('\n'); + +const [N, K] = input.shift().split(' ').map(Number); +const list = input.shift().split(' ').map(Number); +let minLength = Infinity; +let start = 0; +let end = -1; +let count = 0; + +// 초기 위치 찾기 +for (let i = 0; i < list.length; i++) { + if (list[i] === 1) { + if (count === 0) { + start = i; + } + count++; + } + + if (count === K) { + end = i; + minLength = end - start + 1; + break; + } +} + +console.log(findMinLength(start, end)); + +function findMinLength(start, end) { + // K개 이상을 만족하는 집합이 없는 경우 + if (end === -1) { + return -1; + } + + // 다음 구간 탐색 + while (end < list.length) { + if (list[start] === 1) { + count--; + } + start += 1; + end += 1; + if (list[end] === 1) count++; + // 구간 집합 안에 K개의 라이언 인형이 있는 경우 + if (count === K) { + // 범위 재조정 + if (list[start] === 2) { + while (list[start] !== 1 && start < end) { + start++; + } + } + // console.log(start, end); + minLength = end - start + 1; + } + } + + return minLength; +} diff --git "a/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/README.md" "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/README.md" new file mode 100644 index 00000000..32e0547b --- /dev/null +++ "b/BOJ/[15565] \352\267\200\354\227\254\354\232\264 \353\235\274\354\235\264\354\226\270/ksg2388/README.md" @@ -0,0 +1,46 @@ +# [15565] 귀여운 라이언 + +## :pushpin: **Algorithm** + +투포인터, 슬라이딩 윈도우 + +## :round_pushpin: **Logic** + +```javascript +function findMinLength(start, end) { + // K개 이상을 만족하는 집합이 없는 경우 + if (end === -1) { + return -1; + } + + // 다음 구간 탐색 + while (end < list.length) { + if (list[start] === 1) { + count--; + } + start += 1; + end += 1; + if (list[end] === 1) count++; + // 구간 집합 안에 K개의 라이언 인형이 있는 경우 + if (count === K) { + // 범위 재조정 + if (list[start] === 2) { + while (list[start] !== 1 && start < end) { + start++; + } + } + minLength = end - start + 1; + } + } + + return minLength; +} +``` + +- start와 end를 한칸씩 뒤로 밀면서 라이언의 개수를 확인한다. +- 라이언의 개수가 k개가 되는 경우 start가 라이언이 아니라면 start가 라이언이 될때까지 범위를 좁힌다. +- 이후 end가 끝에 도달하기전까지 이 과정을 반복한다. + +## :black_nib: **Review** + +- 슬라이딩 윈도우와 투 포인터를 같이 사용해 해결할 수 있는 문제였다. From ad3d5fe5998f56320bdacf45cda2aad7a98d33a2 Mon Sep 17 00:00:00 2001 From: ksg2388 Date: Wed, 12 Jul 2023 15:55:06 +0900 Subject: [PATCH 2/5] =?UTF-8?q?19week=20:=20BOJ[3584]=20=EA=B0=80=EC=9E=A5?= =?UTF-8?q?=20=EA=B0=80=EA=B9=8C=EC=9A=B4=20=EA=B3=B5=ED=86=B5=20=EC=A1=B0?= =?UTF-8?q?=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ksg2388/Main.js" | 86 +++++++++++++++++++ .../ksg2388/README.md" | 50 +++++++++++ 2 files changed, 136 insertions(+) create mode 100644 "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/ksg2388/Main.js" create mode 100644 "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/ksg2388/README.md" 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/ksg2388/Main.js" "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/ksg2388/Main.js" new file mode 100644 index 00000000..81b15617 --- /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/ksg2388/Main.js" @@ -0,0 +1,86 @@ +const fs = require('fs'); +const filePath = process.platform === 'linux' ? '/dev/stdin' : 'input.txt'; +let input = fs.readFileSync(filePath).toString().trim().split('\n'); + +const T = Number(input.shift()); + +for (let tc = 0; tc < T; tc++) { + const N = Number(input.shift()); + const visited = Array.from({ length: N + 1 }, () => 0); // root 노드를 찾기 위한 배열 + const node = Array.from({ length: N + 1 }, () => []); // 자식 노드의 정보 저장 + const parents = Array.from({ length: N + 1 }, () => 0); + const level = Array.from({ length: N + 1 }, () => 0); + let root = 0; + + for (let i = 1; i < N; i++) { + const [parent, child] = input.shift().split(' ').map(Number); + node[parent].push(child); + parents[child] = parent; + visited[child] = 1; + } + + // root node 찾기 + for (let i = 1; i <= N; i++) { + if (visited[i] === 0) { + root = i; + break; + } + } + // level 설정 + setTreeLevel(root, node, level); + + const [target1, target2] = input.shift().split(' ').map(Number); + + console.log(findCommonAncestor(target1, target2, parents, level)); +} + +function setTreeLevel(root, node, level) { + const start = root; + let count = 1; + level[start] = count++; + const q = []; + + for (let item of node[start]) { + q.push(item); + } + + while (q.length) { + const size = q.length; + + for (let i = 0; i < size; i++) { + const cur = q.shift(); + level[cur] = count; + for (let item of node[cur]) { + q.push(item); + } + } + count++; + } +} + +function findCommonAncestor(a, b, parents, level) { + let lvA = level[a]; + let lvB = level[b]; + // a가 더 높은 레벨인 경우 + if (lvA > lvB) { + const diff = lvA - lvB; + // 레벨 맞추기 + for (let i = 0; i < diff; i++) { + a = parents[a]; + } + } + // b가 더 높은 레벨인 경우 + else if (lvA < lvB) { + const diff = lvB - lvA; + // 레벨 맞추기 + for (let i = 0; i < diff; i++) { + b = parents[b]; + } + } + + while (a !== b) { + a = parents[a]; + b = parents[b]; + } + return a; +} 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/ksg2388/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/ksg2388/README.md" new file mode 100644 index 00000000..701b434b --- /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/ksg2388/README.md" @@ -0,0 +1,50 @@ +# [3584] 가장 가까운 공통 조상 + +## :pushpin: **Algorithm** + +LCA + +## :round_pushpin: **Logic** + +```javascript +const visited = Array.from({ length: N + 1 }, () => 0); // root 노드를 찾기 위한 배열 +const node = Array.from({ length: N + 1 }, () => []); // 자식 노드의 정보 저장 +const parents = Array.from({ length: N + 1 }, () => 0); +const level = Array.from({ length: N + 1 }, () => 0); +``` + +- root 노드를 찾을때 사용할 배열인 `visited`와 자식 노드와 부모 노드의 정보를 저장할 배열, 각 노드의 레벨을 저장할 배열을 각각 만든다. + +```javascript +function setTreeLevel(root, node, level) { + const start = root; + let count = 1; + level[start] = count++; + const q = []; + + for (let item of node[start]) { + q.push(item); + } + + while (q.length) { + const size = q.length; + + for (let i = 0; i < size; i++) { + const cur = q.shift(); + level[cur] = count; + for (let item of node[cur]) { + q.push(item); + } + } + count++; + } +} +``` + +- 두 노드의 높이를 같게 맞춘다. +- 이후 노드의 값이 같아 질때까지 노드의 레벨을 한 칸씩 올린다. + +## :black_nib: **Review** + +- 어디서 들어본 적이 있는 알고리즘이라서 참고 자료를 보지 않고 비슷하게 구현을 하려고 노력했다. +- 그러다보니 배열을 너무 여러개 사용한 것이 좀 신경쓰여서 추가로 다른 사람들의 풀이를 봐야겠다는 생각이 들었다. From 630ae03e5a71c57d5051c8c294ec88b6acd0f2a6 Mon Sep 17 00:00:00 2001 From: ksg2388 Date: Wed, 12 Jul 2023 15:59:54 +0900 Subject: [PATCH 3/5] =?UTF-8?q?19week=20:=20BOJ[1563]=20=EA=B0=9C=EA=B7=BC?= =?UTF-8?q?=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ksg2388/Main.js" | 39 +++++++++++++++++++ .../ksg2388/README.md" | 33 ++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 "BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/Main.js" create mode 100644 "BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/README.md" diff --git "a/BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/Main.js" "b/BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/Main.js" new file mode 100644 index 00000000..a5ed3925 --- /dev/null +++ "b/BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/Main.js" @@ -0,0 +1,39 @@ +const fs = require('fs'); +const filePath = process.platform === 'linux' ? '/dev/stdin' : 'input.txt'; +let input = fs.readFileSync(filePath).toString().trim().split('\n'); + +const N = Number(input); + +const dp = Array.from({ length: 1001 }, () => + Array.from({ length: 2 }, () => Array.from({ length: 3 }, () => 0)) +); + +dp[1][0][0] = 1; +dp[1][0][1] = 1; +dp[1][1][0] = 1; + +for (let i = 1; i < N; i++) { + dp[i + 1][0][0] = (dp[i][0][0] + dp[i][0][1] + dp[i][0][2]) % 1000000; + dp[i + 1][0][1] = dp[i][0][0]; + dp[i + 1][0][2] = dp[i][0][1]; + dp[i + 1][1][0] = + (dp[i][1][0] + + dp[i][1][1] + + dp[i][1][2] + + dp[i][0][0] + + dp[i][0][1] + + dp[i][0][2]) % + 1000000; + dp[i + 1][1][1] = dp[i][1][0]; + dp[i + 1][1][2] = dp[i][1][1]; +} + +const sum = + dp[N][0][0] + + dp[N][0][1] + + dp[N][0][2] + + dp[N][1][0] + + dp[N][1][1] + + dp[N][1][2]; + +console.log(sum % 1000000); diff --git "a/BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/README.md" "b/BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/README.md" new file mode 100644 index 00000000..c8089a0e --- /dev/null +++ "b/BOJ/[1563] \352\260\234\352\267\274\354\203\201/ksg2388/README.md" @@ -0,0 +1,33 @@ +# [1563] 개근상 + +## :pushpin: **Algorithm** + +DP + +## :round_pushpin: **Logic** + +```javascript +for (let i = 1; i < N; i++) { + dp[i + 1][0][0] = (dp[i][0][0] + dp[i][0][1] + dp[i][0][2]) % 1000000; + dp[i + 1][0][1] = dp[i][0][0]; + dp[i + 1][0][2] = dp[i][0][1]; + dp[i + 1][1][0] = + (dp[i][1][0] + + dp[i][1][1] + + dp[i][1][2] + + dp[i][0][0] + + dp[i][0][1] + + dp[i][0][2]) % + 1000000; + dp[i + 1][1][1] = dp[i][1][0]; + dp[i + 1][1][2] = dp[i][1][1]; +} +``` + +- 배열의 첫번째 인덱스에 현재 날짜를 저장하고, 첫번째에 지각, 두번째에 결석일을 저장해둔다. +- 각각의 경우가 될 수 있는 모든 경우의 수를 저장한다. + +## :black_nib: **Review** + +- 보마자마 DP로 풀어야 한다는 생각이 들었는데 도저히 생각이 떠오르지 않았다... +- 간단하게 생각한대로 식을 세우면 됬었는데 너무 어렵게 생각한 것 같다. From e2e585a775d094c5c51155d7a592cd861b9054d1 Mon Sep 17 00:00:00 2001 From: ksg2388 Date: Wed, 12 Jul 2023 16:09:48 +0900 Subject: [PATCH 4/5] =?UTF-8?q?19week=20:=20Programmers[68646]=20=ED=92=8D?= =?UTF-8?q?=EC=84=A0=20=ED=84=B0=ED=8A=B8=EB=A6=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ksg2388/README.md" | 29 +++++++++++++++++++ .../ksg2388/Solution.js" | 17 +++++++++++ 2 files changed, 46 insertions(+) create mode 100644 "Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/README.md" create mode 100644 "Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/Solution.js" diff --git "a/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/README.md" "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/README.md" new file mode 100644 index 00000000..06fd8e0d --- /dev/null +++ "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/README.md" @@ -0,0 +1,29 @@ +# [68646] 풍선 터트리기 + +## :pushpin: **Algorithm** + +구현, 메모이제이션 + +## :round_pushpin: **Logic** + +```javascript +for (let i = 1; i < a.length; i++) { + leftMin[i] = Math.min(leftMin[i - 1], a[i]); + rightMin[a.length - i - 1] = Math.min( + rightMin[a.length - i], + a[a.length - i] + ); +} + +a.forEach((balloon, index) => { + if (balloon <= leftMin[index] || balloon <= rightMin[index]) answer++; +}); +``` + +- 현재 인덱스에서 왼쪽에서의 가장 최소값과 오른쪽에서의 가장 최소값을 저장하는 배열을 만들어 저장해둔다. +- 모든 배열을 돌면서 왼쪽과 오른쪽 중 하나라도 자신보다 큰 값이 있는 경우는 `answer`을 1증가 시킨다. + +## :black_nib: **Review** + +- 방법은 쉽게 떠올렸지만 메모이제이션을 사용하는 법이 바로 떠오르지 않아 시간초과가 났었다. +- 간단한 코드 몇줄로 시간이 엄청나게 줄어든다는건 신기하다... diff --git "a/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/Solution.js" "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/Solution.js" new file mode 100644 index 00000000..ec22b7b4 --- /dev/null +++ "b/Programmers/[68646] \355\222\215\354\204\240 \355\204\260\355\212\270\353\246\254\352\270\260/ksg2388/Solution.js" @@ -0,0 +1,17 @@ +function solution(a) { + let answer = 0; + let leftMin = Array.from({ length: a.length }, () => a[0]); + let rightMin = Array.from({ length: a.length }, () => a[a.length - 1]); + + for (let i = 1; i < a.length; i++) { + leftMin[i] = Math.min(leftMin[i - 1], a[i]); + rightMin[a.length - i - 1] = Math.min( + rightMin[a.length - i], + a[a.length - i] + ); + } + a.forEach((balloon, index) => { + if (balloon <= leftMin[index] || balloon <= rightMin[index]) answer++; + }); + return answer; +} From 56b51d606e7124faabd2335ec755d608598860e5 Mon Sep 17 00:00:00 2001 From: ksg2388 Date: Wed, 12 Jul 2023 16:15:51 +0900 Subject: [PATCH 5/5] =?UTF-8?q?19week=20:=20Programmers[155651]=20?= =?UTF-8?q?=ED=98=B8=ED=85=94=20=EB=8C=80=EC=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ksg2388/README.md" | 48 +++++++++++++++++++ .../ksg2388/Solution.js" | 37 ++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 "Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/README.md" create mode 100644 "Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/Solution.js" diff --git "a/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/README.md" "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/README.md" new file mode 100644 index 00000000..3d5a95b5 --- /dev/null +++ "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/README.md" @@ -0,0 +1,48 @@ +# [155651] 호텔 대실 + +## :pushpin: **Algorithm** + +그리디, 우선순위 큐 + +## :round_pushpin: **Logic** + +```javascript +const change_time = book_time.map((time) => { + const startTime = time[0].split(':').map(Number); + const endTime = time[1].split(':').map(Number); + return [startTime[0] * 60 + startTime[1], endTime[0] * 60 + endTime[1]]; +}); +``` + +- 시작 시간별로 정렬을 하기위해 문자열을 분으로 변경했다. + +```javascript +change_time.forEach((time) => { + if (!q.length) { + q.push(time[1] + 10); + } + + // 대실 가능한 빈 방이 없는 경우 + else if (q[q.length - 1] > time[0]) { + q.push(time[1] + 10); + } else { + // 대실 가능한 경우 + while (q.length) { + if (q[q.length - 1] <= time[0]) { + q.pop(); + } else break; + } + q.push(time[1] + 10); + } + q.sort((a, b) => b - a); + answer = Math.max(answer, q.length); +}); +``` + +- 다음 사람의 입실 시간과 가장 이른 퇴실 시간을 비교하여 입실 시간이 더 늦다면 새로운 방을 배정해준다. + +## :black_nib: **Review** + +- 예전에 비슷한 문제를 풀어서 우선순위 큐를 이용해야겠다고 생각했다. +- 문자열이 정렬이 되지 않아서 일일히 분을 시간으로 치환해서 정렬을 했다. +- 문자열을 다루는데 시간을 너무 잡아먹은 것 같다... diff --git "a/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/Solution.js" "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/Solution.js" new file mode 100644 index 00000000..4a774d70 --- /dev/null +++ "b/Programmers/[155651] \355\230\270\355\205\224 \353\214\200\354\213\244/ksg2388/Solution.js" @@ -0,0 +1,37 @@ +function solution(book_time) { + let answer = 1; + let q = []; + + const change_time = book_time.map((time) => { + const startTime = time[0].split(':').map(Number); + const endTime = time[1].split(':').map(Number); + return [startTime[0] * 60 + startTime[1], endTime[0] * 60 + endTime[1]]; + }); + + change_time.sort((a, b) => { + return a[0] - b[0]; + }); + + change_time.forEach((time) => { + if (!q.length) { + q.push(time[1] + 10); + } + + // 대실 가능한 빈 방이 없는 경우 + else if (q[q.length - 1] > time[0]) { + q.push(time[1] + 10); + } else { + // 대실 가능한 경우 + while (q.length) { + if (q[q.length - 1] <= time[0]) { + q.pop(); + } else break; + } + q.push(time[1] + 10); + } + q.sort((a, b) => b - a); + answer = Math.max(answer, q.length); + }); + + return answer; +}