From 3c172dad9e53841d681a1d76cbef79c40a3cefff Mon Sep 17 00:00:00 2001 From: wogha95 Date: Sun, 22 Sep 2024 10:27:58 +0900 Subject: [PATCH 1/9] solve: reverse linked list --- reverse-linked-list/wogha95.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 reverse-linked-list/wogha95.js diff --git a/reverse-linked-list/wogha95.js b/reverse-linked-list/wogha95.js new file mode 100644 index 000000000..a2a990a03 --- /dev/null +++ b/reverse-linked-list/wogha95.js @@ -0,0 +1,28 @@ +/** + * TC: O(N) + * SC: O(1) + */ + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var reverseList = function (head) { + let pointer = null; + + while (head) { + // 1. 정답 리스트의 맨 앞에 새로운 노드를 추가 + pointer = new ListNode(head.val, pointer); + // 2. head는 다음 노드로 이동 + head = head.next; + } + + return pointer; +}; From 7640bd75a6f151b85f40ea058985730eb218492b Mon Sep 17 00:00:00 2001 From: wogha95 Date: Sun, 22 Sep 2024 13:43:50 +0900 Subject: [PATCH 2/9] solve: longest substring without repeating characters --- .../wogha95.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 longest-substring-without-repeating-characters/wogha95.js diff --git a/longest-substring-without-repeating-characters/wogha95.js b/longest-substring-without-repeating-characters/wogha95.js new file mode 100644 index 000000000..d388f4040 --- /dev/null +++ b/longest-substring-without-repeating-characters/wogha95.js @@ -0,0 +1,51 @@ +/** + * TC: O(S) + * right의 S만큼 순회 + left의 S만큼 순회 + * (각 순회의 곱이 아닌 합인 이유는 right 순회 동안 left의 최대 순회가 S이기 때문입니다.) + * + * SC: O(N) + * usedCharacter에 S만큼 들어갈 수 있습니다. + * + * S: s.length + */ + +/** + * @param {string} s + * @return {number} + */ +var lengthOfLongestSubstring = function (s) { + // 1. 사용된 문자를 기록하기 위한 set + const usedCharacter = new Set(); + + // 2. 정답 제출을 위한 부분문자열 최대 길이 + let maxLength = 0; + + // 3. 순회를 위한 포인터 + 각 index에서 최대 문자열길이를 구하기 위한 변수 + let left = 0; + let right = 0; + + while (left <= right && right < s.length) { + // 4. [right] 문자가 사용되었으면 + if (usedCharacter.has(s[right])) { + // 5. 사용된 문자를 발견하기 전까지 left 이동 (+ 사용된 [left] 문자 기록 제거) + while (s[left] !== s[right]) { + usedCharacter.delete(s[left]); + left += 1; + } + + // 6. [right] 문자와 [left] 문자가 동일하므로 left만 이동 + left += 1; + } else { + // 7. [right] 문자가 미사용되었으면 기록 추가 + usedCharacter.add(s[right]); + } + + // 8. 중복없는 부분문자열 최대 길이 갱신 + maxLength = Math.max(maxLength, right - left + 1); + + // 9. 다음 문자로 이동 + right += 1; + } + + return maxLength; +}; From 11cf061592be60d715b222c246e88eac858d5bbd Mon Sep 17 00:00:00 2001 From: wogha95 Date: Sun, 22 Sep 2024 14:53:48 +0900 Subject: [PATCH 3/9] solve: number of islands --- number-of-islands/wogha95.js | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 number-of-islands/wogha95.js diff --git a/number-of-islands/wogha95.js b/number-of-islands/wogha95.js new file mode 100644 index 000000000..cf5d9b075 --- /dev/null +++ b/number-of-islands/wogha95.js @@ -0,0 +1,80 @@ +/** + * TC: O(ROW * COLUMN) + * 주어진 grid 배열 전체 순회 + (최악의 경우 queue에서 grid 전체 순회) + * + * SC: O(ROW * COLUMN) + * queue에서 최대 grid만큼 순회 + * + * ROW: grid.length, COLUMN: grid[0].length + */ + +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function (grid) { + const LAND = "1"; + const VISITED_LAND = "#"; + const ROW = grid.length; + const COLUMN = grid[0].length; + + // 1. 상하좌우 방향키 + const DIRECTION = [ + { r: 0, c: 1 }, + { r: 1, c: 0 }, + { r: 0, c: -1 }, + { r: -1, c: 0 }, + ]; + + let numberOfIslands = 0; + + // 2. 전체 순회하면서 + for (let row = 0; row < ROW; row++) { + for (let column = 0; column < COLUMN; column++) { + // 3. LAND를 발견하면 방문한 섬으로 표시(bfs)하고 섬갯수 갱신 + if (grid[row][column] === LAND) { + bfs(row, column); + numberOfIslands += 1; + } + } + } + + return numberOfIslands; + + function bfs(startRow, startColumn) { + // 4. 시작좌표 queue에 넣고 방문 표시 + const queue = [[startRow, startColumn]]; + grid[startRow][startColumn] = VISITED_LAND; + + while (queue.length > 0) { + const [row, column] = queue.shift(); + + // 5. 상하좌우의 좌표를 가지고 + for (const direction of DIRECTION) { + const nextRow = row + direction.r; + const nextColumn = column + direction.c; + + // 6. 유효한 좌표 && 미방문 육지인지 확인 + if ( + isValidPosition(nextRow, nextColumn) && + grid[nextRow][nextColumn] === LAND + ) { + // 7. queue에 추가하고 방문 표시 + grid[nextRow][nextColumn] = VISITED_LAND; + queue.push([nextRow, nextColumn]); + } + } + } + } + + // 8. 주어진 2차원 배열의 유효한 좌표인지 확인하는 함수 + function isValidPosition(row, column) { + if (row < 0 || ROW <= row) { + return false; + } + if (column < 0 || COLUMN <= column) { + return false; + } + return true; + } +}; From 86771950c216e5b22a4339dce3ea43c3d6f527e3 Mon Sep 17 00:00:00 2001 From: wogha95 Date: Sun, 22 Sep 2024 17:03:01 +0900 Subject: [PATCH 4/9] solve: unique paths --- unique-paths/wogha95.js | 127 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 unique-paths/wogha95.js diff --git a/unique-paths/wogha95.js b/unique-paths/wogha95.js new file mode 100644 index 000000000..4be8af4e8 --- /dev/null +++ b/unique-paths/wogha95.js @@ -0,0 +1,127 @@ +/** + * 3차 (시간, 공간 복잡도 개선) + * 동일한 down방향, right방향들 중에서 나열하는 방법 + * 즉, ((m - 1) + (n - 1))! / ((m - 1)! * (n - 1)!) + * (+ 팩토리얼의 수는 매우 빠르게 커지므로 중간 나눗셈이 가능할때마다 나누어서 integer 범위를 넘지 않도록 방지) + * + * TC: O(M + N) + * 1부터 최대 (M - 1) + (N + 1)까지 순회 + * + * SC: O(1) + * 계산의 결과 변수가 m, n과 무관하므로 상수의 공간복잡도 + */ + +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function (m, n) { + // 1. down방향, right방향의 수 + const NUMBER_OF_DOWN = m - 1; + const NUMBER_OF_RIGHT = n - 1; + + // 2. factorial 계산을 위한 변수 + let result = 1; + let factorialOfDown = 1; + let factorialOfRight = 1; + + // 3. 'down방향 수 + right방향 수'만큼 순회하면서 + for (let number = 1; number <= NUMBER_OF_DOWN + NUMBER_OF_RIGHT; number++) { + result *= number; + + // 4. factorial 값들이 커지지 않도록 나눌수 있을때마다 나눔 (factorial of down) + if (number <= NUMBER_OF_DOWN) { + factorialOfDown *= number; + if (result % factorialOfDown === 0) { + result /= factorialOfDown; + factorialOfDown = 1; + } + } + + // 5. factorial 값들이 커지지 않도록 나눌수 있을때마다 나눔 (factorial of right) + if (number <= NUMBER_OF_RIGHT) { + factorialOfRight *= number; + if (result % factorialOfRight === 0) { + result /= factorialOfRight; + factorialOfRight = 1; + } + } + } + + return result / factorialOfDown / factorialOfRight; +}; + +/** + * 2차 (공간복잡도 개선) + * 이전 풀이에서 모든 행의 경로수를 기억할 필요가 없는 점을 활용 + * + * TC: O(M * N) + * 경로 수를 기록하기 위한 N배열 순회 * (M - 1) + * + * SC: O(N) + * 경로수 기록을 위한 1차원 배열 + */ + +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function (m, n) { + // 1. 최상단의 경로수는 모두 1 + const numberOfPaths = new Array(n).fill(1); + + for (let row = 1; row < m; row++) { + // 2. 각 좌표의 경로수는 현좌표(1차 풀이의 row-1)와 좌측좌표(1차 풀이의 column-1)의 합 + for (let column = 1; column < n; column++) { + numberOfPaths[column] += numberOfPaths[column - 1]; + } + } + + return numberOfPaths[n - 1]; +}; + +/** + * 1차 + * 각 좌표의 경로수를 기록하여 dp로 풀이 + * 현좌표까지의 경로수 = 상단좌표에서 온 경우 + 좌측좌표에서 온 경우 + * dp[row][column] = dp[row - 1][column] + dp[row][column - 1] + * + * + * TC: O(M * N) + * 경로수를 기록한 2차원 배열을 전체 순회 + * + * SC: O(M * N) + * 경로수 기록을 위한 2차원 배열 + */ + +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function (m, n) { + // 1. 각 좌료까지의 경로수를 기록하기 위한 배열 + const numberOfPaths = new Array(m).fill(new Array(n).fill(0)); + + // 2. 최좌측에 있는 좌표의 경로수는 1 + for (let row = 0; row < m; row++) { + numberOfPaths[row][0] = 1; + } + + // 3. 최상단에 있는 좌표의 경로수는 1 + for (let column = 0; column < n; column++) { + numberOfPaths[0][column] = 1; + } + + // 4. 그 외 각 좌표는 바로 위 좌표(column-1)와 바로 왼쪽 좌표(row-1)의 경로수의 합 + for (let row = 1; row < m; row++) { + for (let column = 1; column < n; column++) { + numberOfPaths[row][column] = + numberOfPaths[row - 1][column] + numberOfPaths[row][column - 1]; + } + } + + return numberOfPaths[m - 1][n - 1]; +}; From 25d31e6ee11c0b19b2e7f5f7bdf515270b532c5c Mon Sep 17 00:00:00 2001 From: wogha95 Date: Mon, 23 Sep 2024 20:06:11 +0900 Subject: [PATCH 5/9] solve: longest substring without repeating characters --- longest-substring-without-repeating-characters/wogha95.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/longest-substring-without-repeating-characters/wogha95.js b/longest-substring-without-repeating-characters/wogha95.js index d388f4040..37b1c7a38 100644 --- a/longest-substring-without-repeating-characters/wogha95.js +++ b/longest-substring-without-repeating-characters/wogha95.js @@ -3,7 +3,7 @@ * right의 S만큼 순회 + left의 S만큼 순회 * (각 순회의 곱이 아닌 합인 이유는 right 순회 동안 left의 최대 순회가 S이기 때문입니다.) * - * SC: O(N) + * SC: O(S) * usedCharacter에 S만큼 들어갈 수 있습니다. * * S: s.length From 4b1c111ef572bb243fad9fd7c7946e65d20c02c9 Mon Sep 17 00:00:00 2001 From: wogha95 Date: Mon, 23 Sep 2024 20:57:43 +0900 Subject: [PATCH 6/9] solve: reverse linked list --- reverse-linked-list/wogha95.js | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/reverse-linked-list/wogha95.js b/reverse-linked-list/wogha95.js index a2a990a03..d294ec1ac 100644 --- a/reverse-linked-list/wogha95.js +++ b/reverse-linked-list/wogha95.js @@ -1,6 +1,47 @@ /** + * 2차 + * Tony님 풀이 참고해서 SC 개선 + * * TC: O(N) * SC: O(1) + * 순회동안 노드 생성하지 않으므로 공간복잡도가 상수다. + * + * N: linked-list length + */ + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var reverseList = function (head) { + let pointer = null; + + while (head !== null) { + let temp = head.next; + head.next = pointer; + pointer = head; + head = temp; + } + + return pointer; +}; + +/** + * 1차 + * TC: O(N) + * linked-list 길이 만큼 순회 + * + * SC: O(N) + * linked-list 길이만큼 생성 + * + * N: linked-list length */ /** From 55a43fc045278dc4c214b897342ae1cab41bf627 Mon Sep 17 00:00:00 2001 From: wogha95 Date: Mon, 23 Sep 2024 20:59:09 +0900 Subject: [PATCH 7/9] solve: unique paths --- unique-paths/wogha95.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unique-paths/wogha95.js b/unique-paths/wogha95.js index 4be8af4e8..9d4ca1a73 100644 --- a/unique-paths/wogha95.js +++ b/unique-paths/wogha95.js @@ -5,7 +5,7 @@ * (+ 팩토리얼의 수는 매우 빠르게 커지므로 중간 나눗셈이 가능할때마다 나누어서 integer 범위를 넘지 않도록 방지) * * TC: O(M + N) - * 1부터 최대 (M - 1) + (N + 1)까지 순회 + * 1부터 최대 (M - 1) + (N - 1)까지 순회 * * SC: O(1) * 계산의 결과 변수가 m, n과 무관하므로 상수의 공간복잡도 From d8b5b1fda8b544a2ed48737d6bc0809794ae7ad4 Mon Sep 17 00:00:00 2001 From: wogha95 Date: Sat, 28 Sep 2024 09:03:10 +0900 Subject: [PATCH 8/9] solve: set matrix zeroes --- set-matrix-zeroes/wogha95.js | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 set-matrix-zeroes/wogha95.js diff --git a/set-matrix-zeroes/wogha95.js b/set-matrix-zeroes/wogha95.js new file mode 100644 index 000000000..01031e386 --- /dev/null +++ b/set-matrix-zeroes/wogha95.js @@ -0,0 +1,45 @@ +/** + * TC: O(ROW * COLUMN) + * SC: O(1) + */ + +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +var setZeroes = function (matrix) { + const ROW = matrix.length; + const COLUMN = matrix[0].length; + + // 1. 0인 요소의 가로, 세로를 특정문자로 변경 + for (let row = 0; row < ROW; row++) { + for (let column = 0; column < COLUMN; column++) { + if (matrix[row][column] === 0) { + changeToChar(row, column, "#"); + } + } + } + + // 2. 특정문자를 모두 0으로 변경 + for (let row = 0; row < ROW; row++) { + for (let column = 0; column < COLUMN; column++) { + if (matrix[row][column] === "#") { + matrix[row][column] = 0; + } + } + } + + // 3. 특정 좌표의 가로, 세로를 char문자로 변경 (대신 0인 요소는 변경하지 않음) + function changeToChar(row, column, char) { + for (let r = 0; r < ROW; r++) { + if (matrix[r][column] !== 0) { + matrix[r][column] = char; + } + } + for (let c = 0; c < COLUMN; c++) { + if (matrix[row][c] !== 0) { + matrix[row][c] = char; + } + } + } +}; From 570f2dac1116c071d1e2c766799f1f4bbd2b3782 Mon Sep 17 00:00:00 2001 From: wogha95 Date: Sat, 28 Sep 2024 22:40:44 +0900 Subject: [PATCH 9/9] solve: set matrix zeroes --- set-matrix-zeroes/wogha95.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/set-matrix-zeroes/wogha95.js b/set-matrix-zeroes/wogha95.js index 01031e386..2549c9454 100644 --- a/set-matrix-zeroes/wogha95.js +++ b/set-matrix-zeroes/wogha95.js @@ -10,12 +10,13 @@ var setZeroes = function (matrix) { const ROW = matrix.length; const COLUMN = matrix[0].length; + const MARK = "#"; // 1. 0인 요소의 가로, 세로를 특정문자로 변경 for (let row = 0; row < ROW; row++) { for (let column = 0; column < COLUMN; column++) { if (matrix[row][column] === 0) { - changeToChar(row, column, "#"); + changeToMark(row, column); } } } @@ -23,22 +24,22 @@ var setZeroes = function (matrix) { // 2. 특정문자를 모두 0으로 변경 for (let row = 0; row < ROW; row++) { for (let column = 0; column < COLUMN; column++) { - if (matrix[row][column] === "#") { + if (matrix[row][column] === MARK) { matrix[row][column] = 0; } } } // 3. 특정 좌표의 가로, 세로를 char문자로 변경 (대신 0인 요소는 변경하지 않음) - function changeToChar(row, column, char) { + function changeToMark(row, column) { for (let r = 0; r < ROW; r++) { if (matrix[r][column] !== 0) { - matrix[r][column] = char; + matrix[r][column] = MARK; } } for (let c = 0; c < COLUMN; c++) { if (matrix[row][c] !== 0) { - matrix[row][c] = char; + matrix[row][c] = MARK; } } }