From b13030c4f7c065ae1e4e0a618c655ca6d7b8194e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sat, 1 Feb 2025 22:07:20 +0900 Subject: [PATCH 01/11] add: solve #225 Linked List Cycle with ts --- linked-list-cycle/Yjaon-K.ts | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 linked-list-cycle/Yjaon-K.ts diff --git a/linked-list-cycle/Yjaon-K.ts b/linked-list-cycle/Yjaon-K.ts new file mode 100644 index 000000000..31eb00430 --- /dev/null +++ b/linked-list-cycle/Yjaon-K.ts @@ -0,0 +1,37 @@ +/** + * Definition for singly-linked list. + * class ListNode { + * val: number + * next: ListNode | null + * constructor(val?: number, next?: ListNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + * } + */ + +/** + * 연결 리스트인가 순환하는지 여부 확인 + * @param {ListNode} head - ListNode + * @returns {boolean} - 순환 여부 + * + * 시간 복잡도: O(n) + * + * 공간 복잡도: O(n) + * - 노드의 개수만큼 Set에 저장 + */ +function hasCycle(head: ListNode | null): boolean { + const set = new Set(); + + while (head) { + if (set.has(head)) { + return true; + } + + set.add(head); + head = head.next; + } + + return false; +} + From 4e048790da4b9ad22b41900d22516d4222fc5828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sun, 2 Feb 2025 15:24:38 +0900 Subject: [PATCH 02/11] add: solve #245 Find Minimum in Rotated Sorted Array with ts --- .../Yjason-K.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 find-minimum-in-rotated-sorted-array/Yjason-K.ts diff --git a/find-minimum-in-rotated-sorted-array/Yjason-K.ts b/find-minimum-in-rotated-sorted-array/Yjason-K.ts new file mode 100644 index 000000000..beb4eb5ae --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/Yjason-K.ts @@ -0,0 +1,31 @@ +/** + * 배열에서 가장 작은 수 찾기 ( 제약 : 시간 복잡도 O(log n) ) + * @param {number[]} nums 회전된 수 배열 + * + * 시간 복잡되: O(log n) + * - 이분 탐색을 사용하여 최소값을 탐색 + * + * 공간 복잡도: O(1) + */ +function findMin(nums: number[]): number { + let left = 0, right = nums.length - 1; + + while (left <= right) { + let mid = Math.floor((left + right) / 2); + + // 정렬이 망가진 경우 + if (nums[mid] < nums[mid-1]) return nums[mid]; + + // left, right 범위 줄여나가기 + if (nums[0] < nums[mid]){ + left = mid + 1; + } else { + right = mid - 1; + } + } + + // 탐색 후에도 찾지 못한 경우 회전되지 않은 경우 + return nums[0]; + +} + From f8653b257aeb47cc67a124d217480ebdc6ff81d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Mon, 3 Feb 2025 22:44:58 +0900 Subject: [PATCH 03/11] add: solve #270 Maximum Product SubArray with ts --- maximum-product-subarray/Yjason-K.ts | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 maximum-product-subarray/Yjason-K.ts diff --git a/maximum-product-subarray/Yjason-K.ts b/maximum-product-subarray/Yjason-K.ts new file mode 100644 index 000000000..c0f3fe86b --- /dev/null +++ b/maximum-product-subarray/Yjason-K.ts @@ -0,0 +1,31 @@ +/** + * subArray 중 최대 곱을 구하는 함수 + * @param {number[]} nums - 숫자 배열 + * @returns {number} - subArray 중 최대 곱 + * + * @description 음수의 곱이 존재 할 수 있기 때문에, 최대 값과 최소값을 갱신하며, 결과 값을 갱신. + * + * 시간 복잡도 : O(n) + * - nums 배열 1회 순회 + * + * 공간 복잡도 : O(1) + */ +function maxProduct(nums: number[]): number { + let max = nums[0]; + let min = nums[0]; + let result = nums[0]; + + // 첫 번째 요소를 제외한 모든 요소를 탐색 + for (let i = 1; i < nums.length; i++) { + let current = nums[i] + + // 현재 값, 이전 최대 곱과의 곱, 이전 최소 곱과의 곱 중 최대/최소 갱신 + const cases = [current * max, current * min, current]; + + max = Math.max(...cases); + min = Math.min(...cases); + result = Math.max(result, max); + } + + return result; +} \ No newline at end of file From 57d73bad45334a5afc0d42a8e5f7771348b5d7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Tue, 4 Feb 2025 23:01:04 +0900 Subject: [PATCH 04/11] add: solve #260 Pacific Atlantic Water Flow with ts --- pacific-atlantic-water-flow/Yjason-K.ts | 76 +++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 pacific-atlantic-water-flow/Yjason-K.ts diff --git a/pacific-atlantic-water-flow/Yjason-K.ts b/pacific-atlantic-water-flow/Yjason-K.ts new file mode 100644 index 000000000..81b76aacc --- /dev/null +++ b/pacific-atlantic-water-flow/Yjason-K.ts @@ -0,0 +1,76 @@ +/** + * 깊이 우선 탐색(DFS)을 사용하여 특정 바다에서 올라갈 수 있는 좌표을 저장 + * @param i 현재 위치의 행 (row) + * @param j 현재 위치의 열 (column) + * @param visited 방문한 좌표를 저장하는 Set (바다에서 도달할 수 있는 위치를 저장) + * @param heights 높이 정보가 담긴 2차원 배열 + * + * 시간 복잡도: O(m × n) + * - 각 셀은 최대 한 번 방문하며, 총 m × n개의 셀을 탐색함 + * + * 공간 복잡도: O(m × n) + * - `visited` Set에 최대 m × n개의 좌표를 저장 가능 + * - 재귀 호출 스택의 깊이는 O(m + n) (최악의 경우 가장 긴 경로를 따라 탐색) + */ +function dfs(i: number, j: number, visited: Set, heights: number[][]) { + if (visited.has(`${i},${j}`)) return; + + visited.add(`${i},${j}`); + + for (const [di, dj] of [[-1, 0], [1, 0], [0, -1], [0, 1]]) { + const newI = i + di; + const newJ = j + dj; + + if ( + newI >= 0 && newI < heights.length && + newJ >= 0 && newJ < heights[0].length && + heights[newI][newJ] >= heights[i][j] + ) { + dfs(newI, newJ, visited, heights); + } + } +}; + +/** + * 두 바다 모두 도달할 수 있는 좌표를 찾는 함수 + * + * @param heights 2차원 배열로 이루어진 지형의 높이 정보 + * @returns 두 바다 모두 도달할 수 있는 좌표 배열 + * + * 시간 복잡도: O(m × n) + * - 태평양 및 대서양에서 각각 DFS 수행 → O(m × n) + * - 결과를 찾는 이중 루프 → O(m × n) + * + * 공간 복잡도: O(m × n) + * - `pacificSet`과 `atlanticSet`에 최대 O(m × n)개의 좌표 저장 + * + */ +function pacificAtlantic(heights: number[][]): number[][] { + if (!heights || heights.length === 0 || heights[0].length === 0) return []; + + const rows = heights.length; + const cols = heights[0].length; + + const pacificSet = new Set(); + const atlanticSet = new Set(); + + // 태평양(왼쪽, 위쪽)에서 출발하는 DFS + for (let i = 0; i < rows; i++) dfs(i, 0, pacificSet, heights); + for (let j = 0; j < cols; j++) dfs(0, j, pacificSet, heights); + + // 대서양(오른쪽, 아래쪽)에서 출발하는 DFS + for (let i = 0; i < rows; i++) dfs(i, cols - 1, atlanticSet, heights); + for (let j = 0; j < cols; j++) dfs(rows - 1, j, atlanticSet, heights); + + const result: number[][] = []; + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (pacificSet.has(`${i},${j}`) && atlanticSet.has(`${i},${j}`)) { + result.push([i, j]); + } + } + } + + return result; +}; + From 0ed299b6ce9e3ee6bdcc76407a6bd9bcef9ac0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sat, 8 Feb 2025 15:47:14 +0900 Subject: [PATCH 05/11] fix: add line break --- maximum-product-subarray/Yjason-K.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/maximum-product-subarray/Yjason-K.ts b/maximum-product-subarray/Yjason-K.ts index c0f3fe86b..9eed79489 100644 --- a/maximum-product-subarray/Yjason-K.ts +++ b/maximum-product-subarray/Yjason-K.ts @@ -28,4 +28,5 @@ function maxProduct(nums: number[]): number { } return result; -} \ No newline at end of file +} + From 495139f162b0dd61d0028787502f30e2f7571fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sat, 8 Feb 2025 15:48:53 +0900 Subject: [PATCH 06/11] fix: modify filename --- linked-list-cycle/{Yjaon-K.ts => Yjason-K.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename linked-list-cycle/{Yjaon-K.ts => Yjason-K.ts} (100%) diff --git a/linked-list-cycle/Yjaon-K.ts b/linked-list-cycle/Yjason-K.ts similarity index 100% rename from linked-list-cycle/Yjaon-K.ts rename to linked-list-cycle/Yjason-K.ts From 43e2c5399e446e1fa3d5d4518b637d702a022f1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sun, 9 Feb 2025 23:00:02 +0900 Subject: [PATCH 07/11] add: solve #226 Invert Binary Tree with ts --- invert-binary-tree/Yjason-K.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 invert-binary-tree/Yjason-K.ts diff --git a/invert-binary-tree/Yjason-K.ts b/invert-binary-tree/Yjason-K.ts new file mode 100644 index 000000000..0d44b9f37 --- /dev/null +++ b/invert-binary-tree/Yjason-K.ts @@ -0,0 +1,25 @@ +/** + * 이진 트리를 반전시키는 함수 + * @param {TreeNode | null} root - 반전할 이진 트리의 루트 노드 + * @returns {TreeNode | null} - 반전된 이진 트리의 루트 노드 + * + * 시간 복잡도: O(n) + * - 트리의 모든 노드를 한 번씩 방문해야 하므로 선형 시간 복잡도를 가짐 + * 공간 복잡도: O(h) + * - 재귀 호출에 의해 최대 트리의 높이(h)만큼의 호출 스택이 필요 + */ +function invertTree(root: TreeNode | null): TreeNode | null { + // 루트가 null이면 null 반환 + if (!root) return null; + + // 왼쪽과 오른쪽 서브트리를 재귀적으로 반전 + const left = invertTree(root.left); + const right = invertTree(root.right); + + // 현재 노드의 왼쪽과 오른쪽 서브트리를 교환 + root.left = right; + root.right = left; + + // 반전된 루트 노드를 반환 + return root; + } \ No newline at end of file From e0d57611fcf5bda003656119c32e26cf6a2e9e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sun, 9 Feb 2025 23:24:27 +0900 Subject: [PATCH 08/11] fix: #226 add line break --- invert-binary-tree/Yjason-K.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/invert-binary-tree/Yjason-K.ts b/invert-binary-tree/Yjason-K.ts index 0d44b9f37..26fc1cf89 100644 --- a/invert-binary-tree/Yjason-K.ts +++ b/invert-binary-tree/Yjason-K.ts @@ -22,4 +22,6 @@ function invertTree(root: TreeNode | null): TreeNode | null { // 반전된 루트 노드를 반환 return root; - } \ No newline at end of file + } + + \ No newline at end of file From 1e367bd9bfc7b4ee713ef1980228f1bd6373e53c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Sun, 9 Feb 2025 23:25:13 +0900 Subject: [PATCH 09/11] solve: add #246 Search In Rotated Sorted Array with ts --- search-in-rotated-sorted-array/Yjason-K.ts | 55 ++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 search-in-rotated-sorted-array/Yjason-K.ts diff --git a/search-in-rotated-sorted-array/Yjason-K.ts b/search-in-rotated-sorted-array/Yjason-K.ts new file mode 100644 index 000000000..0dbcb1b7c --- /dev/null +++ b/search-in-rotated-sorted-array/Yjason-K.ts @@ -0,0 +1,55 @@ +// similar problem to #245 Find Minimum In Rotated Sorted Array +/** + * 회정된 배열에서 target의 index를 찾는 문제 + * @param {number[]} nums - 회전된 배열 + * @param target - 찾는 수 + * @returns {number} - target의 index + * + * 시간 복잡도: O(log n) + * - 이분 탐색을 사용하여 최적의 탐색을 수행 + * + * 공간 복잡도: O(1) + * - 추가적인 공간 사용 없이 포인터만 이용하여 탐색 + */ +function search(nums: number[], target: number): number { + let left = 0, right = nums.length - 1; + + while (left <= right) { + let mid = Math.floor((left + right) / 2); + + if (nums[mid] === target) return mid; + + // mid를 기준으로 왼쪽 부분이 정렬된 경우 + if (nums[left] <= nums[mid]) { + /** + * 왼쪽 부분이 오름차순 정렬되어 있다면: + * - nums[left] ~ nums[mid] 범위는 정렬되어 있음 + * - target이 이 범위 내에 있다면, right를 줄여서 탐색 + * - 아니라면 target은 오른쪽에 있으므로 left를 증가시켜 탐색 + */ + if (nums[left] <= target && target < nums[mid]) { + right = mid - 1; // 왼쪽 범위에서 탐색 + } else { + left = mid + 1; // 오른쪽 범위에서 탐색 + } + } + // mid를 기준으로 오른쪽 부분이 정렬된 경우 + else { + /** + * 오른쪽 부분이 오름차순 정렬되어 있다면: + * - nums[mid] ~ nums[right] 범위는 정렬되어 있음 + * - target이 이 범위 내에 있다면, left를 늘려서 탐색 + * - 아니라면 target은 왼쪽에 있으므로 right를 감소시켜 탐색 + */ + if (nums[mid] < target && target <= nums[right]) { + left = mid + 1; // 오른쪽 범위에서 탐색 + } else { + right = mid - 1; // 왼쪽 범위에서 탐색 + } + } + } + + // target을 찾지 못한 경우 + return -1; +} + From 1e3251ae5b57dcbf36d82a33be00d9da5a9f910e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Mon, 10 Feb 2025 20:55:41 +0900 Subject: [PATCH 10/11] Revert "Merge branch 'DaleStudy:main' into main" This reverts commit dcde7b3e8c9dc6966ec1eb91965fa032a435430b, reversing changes made to 42ae345e42ac926c211a016db75b42c6a830e185. --- clone-graph/forest000014.java | 2 +- .../Chaedie.py | 40 ------- .../Jeehay28.js | 49 -------- .../YeomChaeeun.ts | 37 ------ .../dusunax.py | 41 ------- .../ekgns33.java | 56 --------- .../eunhwa99.java | 17 --- .../forest000014.java | 38 ------ .../gmlwls96.kt | 24 ---- .../mike2ox.ts | 44 ------- .../mintheon.java | 13 -- .../mmyeon.ts | 28 ----- find-minimum-in-rotated-sorted-array/pmjuu.py | 22 ---- .../yolophg.py | 22 ---- linked-list-cycle/Chaedie.py | 24 ---- linked-list-cycle/EcoFriendlyAppleSu.kt | 21 ---- linked-list-cycle/Jeehay28.js | 39 ------ linked-list-cycle/YeomChaeeun.ts | 45 ------- linked-list-cycle/bus710.go | 94 --------------- linked-list-cycle/dusunax.py | 33 ------ linked-list-cycle/ekgns33.java | 35 ------ linked-list-cycle/eunhwa99.java | 36 ------ linked-list-cycle/forest000014.java | 29 ----- linked-list-cycle/gmlwls96.kt | 16 --- linked-list-cycle/limlimjo.js | 29 ----- linked-list-cycle/mike2ox.ts | 39 ------ linked-list-cycle/mintheon.java | 28 ----- linked-list-cycle/mmyeon.ts | 61 ---------- linked-list-cycle/pmjuu.py | 28 ----- linked-list-cycle/yolophg.py | 21 ---- .../EcoFriendlyAppleSu.kt | 63 ---------- .../gmlwls96.kt | 16 +++ maximum-product-subarray/Chaedie.py | 37 ------ maximum-product-subarray/Jeehay28.js | 74 ------------ maximum-product-subarray/YeomChaeeun.ts | 31 ----- maximum-product-subarray/dusunax.py | 31 ----- maximum-product-subarray/ekgns33.java | 45 ------- maximum-product-subarray/eunhwa99.java | 26 ---- maximum-product-subarray/forest000014.java | 89 -------------- maximum-product-subarray/gmlwls96.kt | 15 --- maximum-product-subarray/mike2ox.ts | 40 ------- maximum-product-subarray/mintheon.java | 26 ---- maximum-product-subarray/mmyeon.ts | 31 ----- maximum-product-subarray/pmjuu.py | 24 ---- maximum-product-subarray/yolophg.py | 25 ---- minimum-window-substring/Jeehay28.js | 63 ---------- minimum-window-substring/dusunax.py | 68 ----------- minimum-window-substring/ekgns33.java | 30 ----- minimum-window-substring/gmlwls96.kt | 32 ----- minimum-window-substring/mmyeon.ts | 69 ----------- minimum-window-substring/yolophg.py | 40 ------- pacific-atlantic-water-flow/Chaedie.py | 33 ------ pacific-atlantic-water-flow/Jeehay28.js | 111 ------------------ pacific-atlantic-water-flow/dusunax.py | 42 ------- pacific-atlantic-water-flow/ekgns33.java | 62 ---------- pacific-atlantic-water-flow/eunhwa99.java | 63 ---------- pacific-atlantic-water-flow/mike2ox.ts | 75 ------------ pacific-atlantic-water-flow/mmyeon.ts | 76 ------------ pacific-atlantic-water-flow/pmjuu.py | 71 ----------- pacific-atlantic-water-flow/yolophg.py | 44 ------- 60 files changed, 17 insertions(+), 2446 deletions(-) delete mode 100644 find-minimum-in-rotated-sorted-array/Chaedie.py delete mode 100644 find-minimum-in-rotated-sorted-array/Jeehay28.js delete mode 100644 find-minimum-in-rotated-sorted-array/YeomChaeeun.ts delete mode 100644 find-minimum-in-rotated-sorted-array/dusunax.py delete mode 100644 find-minimum-in-rotated-sorted-array/ekgns33.java delete mode 100644 find-minimum-in-rotated-sorted-array/eunhwa99.java delete mode 100644 find-minimum-in-rotated-sorted-array/forest000014.java delete mode 100644 find-minimum-in-rotated-sorted-array/gmlwls96.kt delete mode 100644 find-minimum-in-rotated-sorted-array/mike2ox.ts delete mode 100644 find-minimum-in-rotated-sorted-array/mintheon.java delete mode 100644 find-minimum-in-rotated-sorted-array/mmyeon.ts delete mode 100644 find-minimum-in-rotated-sorted-array/pmjuu.py delete mode 100644 find-minimum-in-rotated-sorted-array/yolophg.py delete mode 100644 linked-list-cycle/Chaedie.py delete mode 100644 linked-list-cycle/EcoFriendlyAppleSu.kt delete mode 100644 linked-list-cycle/Jeehay28.js delete mode 100644 linked-list-cycle/YeomChaeeun.ts delete mode 100644 linked-list-cycle/bus710.go delete mode 100644 linked-list-cycle/dusunax.py delete mode 100644 linked-list-cycle/ekgns33.java delete mode 100644 linked-list-cycle/eunhwa99.java delete mode 100644 linked-list-cycle/forest000014.java delete mode 100644 linked-list-cycle/gmlwls96.kt delete mode 100644 linked-list-cycle/limlimjo.js delete mode 100644 linked-list-cycle/mike2ox.ts delete mode 100644 linked-list-cycle/mintheon.java delete mode 100644 linked-list-cycle/mmyeon.ts delete mode 100644 linked-list-cycle/pmjuu.py delete mode 100644 linked-list-cycle/yolophg.py delete mode 100644 longest-common-subsequence/EcoFriendlyAppleSu.kt create mode 100644 longest-substring-without-repeating-characters/gmlwls96.kt delete mode 100644 maximum-product-subarray/Chaedie.py delete mode 100644 maximum-product-subarray/Jeehay28.js delete mode 100644 maximum-product-subarray/YeomChaeeun.ts delete mode 100644 maximum-product-subarray/dusunax.py delete mode 100644 maximum-product-subarray/ekgns33.java delete mode 100644 maximum-product-subarray/eunhwa99.java delete mode 100644 maximum-product-subarray/forest000014.java delete mode 100644 maximum-product-subarray/gmlwls96.kt delete mode 100644 maximum-product-subarray/mike2ox.ts delete mode 100644 maximum-product-subarray/mintheon.java delete mode 100644 maximum-product-subarray/mmyeon.ts delete mode 100644 maximum-product-subarray/pmjuu.py delete mode 100644 maximum-product-subarray/yolophg.py delete mode 100644 minimum-window-substring/Jeehay28.js delete mode 100644 minimum-window-substring/dusunax.py delete mode 100644 minimum-window-substring/ekgns33.java delete mode 100644 minimum-window-substring/gmlwls96.kt delete mode 100644 minimum-window-substring/mmyeon.ts delete mode 100644 minimum-window-substring/yolophg.py delete mode 100644 pacific-atlantic-water-flow/Chaedie.py delete mode 100644 pacific-atlantic-water-flow/Jeehay28.js delete mode 100644 pacific-atlantic-water-flow/dusunax.py delete mode 100644 pacific-atlantic-water-flow/ekgns33.java delete mode 100644 pacific-atlantic-water-flow/eunhwa99.java delete mode 100644 pacific-atlantic-water-flow/mike2ox.ts delete mode 100644 pacific-atlantic-water-flow/mmyeon.ts delete mode 100644 pacific-atlantic-water-flow/pmjuu.py delete mode 100644 pacific-atlantic-water-flow/yolophg.py diff --git a/clone-graph/forest000014.java b/clone-graph/forest000014.java index 99fc4e4fe..60c0a2b25 100644 --- a/clone-graph/forest000014.java +++ b/clone-graph/forest000014.java @@ -70,7 +70,7 @@ public void dfs(Node oldNode) { Node newNeighbor = createNode(oldNeighbor.val); newNode.neighbors.add(newNeighbor); newNeighbor.neighbors.add(newNode); - dfs(oldNeighbor); + dfs(oldNeighbor, newNeighbor); } } } diff --git a/find-minimum-in-rotated-sorted-array/Chaedie.py b/find-minimum-in-rotated-sorted-array/Chaedie.py deleted file mode 100644 index 966790821..000000000 --- a/find-minimum-in-rotated-sorted-array/Chaedie.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Solution: - 1) 순회하며 이전 값이 현재 값보다 크거나 같다면 현재 값이 최소값이다. - 2) 끝까지 돌아도 최소값이 없을 경우 첫번쨰 값이 최소값이다. -Time: O(n) -Space: O(1) -""" - - -class Solution: - def findMin(self, nums: List[int]) -> int: - for i in range(1, len(nums)): - if nums[i - 1] >= nums[i]: - return nums[i] - - return nums[0] - - """ - Solution: - 시간 복잡도 O(log n)으로 풀기 위해 binary search 사용 - Time: O(log n) - Space: O(1) - """ - - def findMin(self, nums: List[int]) -> int: - l, r = 1, len(nums) - 1 - - while l <= r: - mid = (l + r) // 2 - # prev 값보다 mid 가 작으면 찾던 값 - if nums[mid - 1] > nums[mid]: - return nums[mid] - # mid 까지 정상 순서면 우측 탐색 - if nums[0] < nums[mid]: - l = mid + 1 - # mid 까지 비 정상 순서면 좌측 탐색 - else: - r = mid - 1 - # 못찾을 경우 전체 정상 순서 케이스 - return nums[0] diff --git a/find-minimum-in-rotated-sorted-array/Jeehay28.js b/find-minimum-in-rotated-sorted-array/Jeehay28.js deleted file mode 100644 index e856cfabc..000000000 --- a/find-minimum-in-rotated-sorted-array/Jeehay28.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @param {number[]} nums - * @return {number} - */ - -// Binary Search -// Time Complexity: O(log n) (Binary search halving the search space each step) -// Space Complexity: O(1) (No extra space except for a few variables) -var findMin = function (nums) { - // Example Rotations: - // nums = [0,1,2,4,5,6,7] - // [4,5,6,7,0,1,2] -> Rotated 4 times - // [0,1,2,4,5,6,7] -> 7 times rotated - - // Initial State: - // [4, 5, 6, 7, 0, 1, 2] - // ↑ ↑ - // (left) (right) - // - // Find mid: - // [4, 5, 6, 7, 0, 1, 2] - // ↑ 🎯 ↑ - // (left) (mid) (right) - // - // If nums[mid] > nums[right], move left to search in the right half: - // [4, 5, 6, 7, 0, 1, 2] - // ↑ ↑ - // (left) (right) - - let left = 0; - let right = nums.length - 1; - - while (left < right) { - let mid = Math.floor((left + right) / 2); - - if (nums[mid] > nums[right]) { - // Minimum must be in the right half - // Need to update left to search in the right half - left = mid + 1; - } else { - // Minimum is in the left half (including mid) - // Need to update right to search in the left half - right = mid; - } - } - - return nums[left]; -}; - diff --git a/find-minimum-in-rotated-sorted-array/YeomChaeeun.ts b/find-minimum-in-rotated-sorted-array/YeomChaeeun.ts deleted file mode 100644 index 2b4918a44..000000000 --- a/find-minimum-in-rotated-sorted-array/YeomChaeeun.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * 정렬된 배열에서 최소값 찾기 - * 알고리즘 복잡도 - * - 시간 복잡도: O(logn) - * - 공간 복잡도: O(1) - * @param nums - */ -function findMin(nums: number[]): number { - // 풀이 1 - sort() 사용 - // 시간 복잡도: O(nlogn) / 공간 복잡도: O(1) - // nums.sort((a, b) => a - b) - // return nums[0] - - // 풀이 2 - 배열이 정렬되어 있음을 활용한 풀이 - // 시간 복잡도: O(n) / 공간 복잡도: O(1) - // let min = nums[0]; - // for(let i = 1; i < nums.length; i++) { - // console.log(nums[i]) - // min = Math.min(nums[i], min) - // } - // return min - - // 이분 탐색법 활용 - // 절반씩 잘라서 nums[n-1] > nums[n] 의 지점을 찾는다 - let low = 0; - let high = nums.length - 1; - while(low < high) { - let mid = low + Math.floor((high - low) / 2); - - if(nums[mid] > nums[high]) { - low = mid + 1; - } else { - high = mid; - } - } - return nums[low] -} diff --git a/find-minimum-in-rotated-sorted-array/dusunax.py b/find-minimum-in-rotated-sorted-array/dusunax.py deleted file mode 100644 index 80241dbc2..000000000 --- a/find-minimum-in-rotated-sorted-array/dusunax.py +++ /dev/null @@ -1,41 +0,0 @@ -''' -# 153. Find Minimum in Rotated Sorted Array - -> **why binary search works in a "rotated" sorted array?** -> rotated sorted array consists of **two sorted subarrays**, and the minimum value is the second sorted subarray's first element. -> so 👉 find the point that second sorted subarray starts. -> -> - if nums[mid] > nums[right]? => the pivot point is in the right half. -> - if nums[mid] <= nums[right]? => the pivot point is in the left half. -> - loop until left and right are the same. -''' -class Solution: - ''' - ## A. brute force(not a solution) - - TC: O(n) - - SC: O(1) - ''' - def findMinBF(self, nums: List[int]) -> int: - if len(nums) == 1: - return nums[0] - - return min(nums) # check all elements - - ''' - ## B. binary search - - TC: O(log n) - - SC: O(1) - ''' - def findMinBS(self, nums: List[int]) -> int: - left = 0 - right = len(nums) - 1 - - while left < right: - mid = (left + right) // 2 - - if nums[mid] > nums[right]: - left = mid + 1 - else: - right = mid - - return nums[left] diff --git a/find-minimum-in-rotated-sorted-array/ekgns33.java b/find-minimum-in-rotated-sorted-array/ekgns33.java deleted file mode 100644 index d81080909..000000000 --- a/find-minimum-in-rotated-sorted-array/ekgns33.java +++ /dev/null @@ -1,56 +0,0 @@ -/** - input : array of integers - output : minimum element's value - - 3 4 5 1 2 - draw graph - - 5 - 4 - 3 - 2 - 1 - l r - l r - l r - -------------- - 5 - 4 - 3 - 2 - 1 - mid right - -------------- - left < right ->> sorted. - left < mid ->> don't have to search range [left, mid] - mid > right ->> rotation point is between [mid, right]; - - solution 1) brute force - read the array - - tc : O(n) - sc : O(1); - - solution 2) binary search - do binary search, move pointers with descripted conditions - after binary search loop ends, the left pointer is the minimum element - - tc : O(logn) - sc : O(1) - */ - -class Solution { - public int findMin(int[] nums) { - int l = 0; - int r = nums.length - 1; - while(l < r) { - int mid = (r - l) / 2 + l; - if(nums[mid] < nums[r]) { - r = mid; - } else { - l = mid + 1; - } - } - return nums[l]; - } -} diff --git a/find-minimum-in-rotated-sorted-array/eunhwa99.java b/find-minimum-in-rotated-sorted-array/eunhwa99.java deleted file mode 100644 index 23d94a5a0..000000000 --- a/find-minimum-in-rotated-sorted-array/eunhwa99.java +++ /dev/null @@ -1,17 +0,0 @@ -class Solution { - // TC: O(log N) - // SC: O(1) - public int findMin(int[] nums) { - int left = 0; - int right = nums.length - 1; - while (left < right) { - int mid = left + (right - left) / 2; - if (nums[mid] < nums[right]) { - right = mid; - } else { - left = mid + 1; - } - } - return nums[left]; - } -} diff --git a/find-minimum-in-rotated-sorted-array/forest000014.java b/find-minimum-in-rotated-sorted-array/forest000014.java deleted file mode 100644 index 7f03d0312..000000000 --- a/find-minimum-in-rotated-sorted-array/forest000014.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -# Time Complexity: O(logn) -# Space Complexity: O(1) - -binary search를 사용해 접근했습니다. -sorted array인 경우는 while문 시작 전, 예외 체크를 했습니다. -binary search를 진행하면, 각각의 loop의 mid 원소는 아래 4가지 경우 중 하나입니다. -maximum / minimum / 앞쪽 수열의 원소 중 하나 / 뒤쪽 수열의 원소 중 하나 -maximum이거나 minimum인 경우는 더 이상 탐색할 필요 없이 종료합니다. -앞쪽 수열인 경우, 우리가 원하는 minimum은 왼쪽에는 없으므로, left 포인터를 mid의 오른쪽으로 옮기고 다음 loop를 진행하고, -뒤쪽 수열인 경우, 우리가 원하는 minimum은 오른쪽에는 없으므로, rigth 포인터를 mid의 왼쪽으로 옮기고 다음 loop를 진행합니다. - - */ -class Solution { - public int findMin(int[] nums) { - int l = 0; - int r = nums.length - 1; - - if (nums[l] <= nums[r]) { // sorted array인 경우 (size가 1인 경우도 포함) - return nums[l]; - } - - while (l <= r) { - int m = (r - l) / 2 + l; // 만약 문제 조건상 l, r의 합이 int 범위를 넘어가서 overflow가 생길 수 있는 경우에, 이런 식으로 overflow를 방지할 수 있다고 알고 있습니다. 이 문제는 overflow 걱정은 없지만, 나중에 실전에서 나오면 잊지 않으려고 이렇게 구현해보았습니다. - if (m > 0 && nums[m - 1] > nums[m]) { - return nums[m]; - } else if (m < nums.length - 1 && nums[m] > nums[m + 1]) { - return nums[m + 1]; - } else if (nums[m] > nums[l]) { - l = m + 1; - } else { - r = m - 1; - } - } - - return -1; - } -} diff --git a/find-minimum-in-rotated-sorted-array/gmlwls96.kt b/find-minimum-in-rotated-sorted-array/gmlwls96.kt deleted file mode 100644 index b28d5781d..000000000 --- a/find-minimum-in-rotated-sorted-array/gmlwls96.kt +++ /dev/null @@ -1,24 +0,0 @@ -class Solution { - // 시간 : O(logN) 공간 : O(1) - // 이분탐색. - fun findMin(nums: IntArray): Int { - var left = 0 - var right = nums.lastIndex - - while (left <= right){ - val mid = (left + right)/2 - when{ - nums[mid-1] > nums[mid] -> { - return nums[mid] - } - nums[0] < nums[mid] -> { - left = mid + 1 - } - else -> { - right = mid -1 - } - } - } - return nums[0] - } -} diff --git a/find-minimum-in-rotated-sorted-array/mike2ox.ts b/find-minimum-in-rotated-sorted-array/mike2ox.ts deleted file mode 100644 index 9e83b6340..000000000 --- a/find-minimum-in-rotated-sorted-array/mike2ox.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Source: https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/ - * 풀이방법: 이진 탐색을 이용하여 최솟값을 찾음 - * - * 시간복잡도: O(log n) - * 공간복잡도: O(1) - */ - -function findMin(nums: number[]): number { - // 배열의 길이가 1인 경우 - if (nums.length === 1) return nums[0]; - - let left: number = 0; - let right: number = nums.length - 1; - - // 이미 정렬된 경우 - if (nums[right] > nums[0]) { - return nums[0]; - } - - // 이진 탐색 - while (left <= right) { - const mid: number = Math.floor((left + right) / 2); - - // 최솟값을 찾는 조건들 - if (nums[mid] > nums[mid + 1]) { - return nums[mid + 1]; - } - if (nums[mid - 1] > nums[mid]) { - return nums[mid]; - } - - // 탐색 범위 조정 - if (nums[mid] > nums[0]) { - // 최솟값은 중간점 이후에 있음 - left = mid + 1; - } else { - // 최솟값은 중간점 이전에 있음 - right = mid - 1; - } - } - - return nums[0]; // 기본값 반환 -} diff --git a/find-minimum-in-rotated-sorted-array/mintheon.java b/find-minimum-in-rotated-sorted-array/mintheon.java deleted file mode 100644 index ad0b69561..000000000 --- a/find-minimum-in-rotated-sorted-array/mintheon.java +++ /dev/null @@ -1,13 +0,0 @@ -class Solution { - // 시간복잡도: O(n) - // 공간복잡도: O(1) - public int findMin(int[] nums) { - for(int i = 1; i < nums.length; i++) { - if(nums[i - 1] > nums[i]) { - return nums[i]; - } - } - - return nums[0]; - } -} diff --git a/find-minimum-in-rotated-sorted-array/mmyeon.ts b/find-minimum-in-rotated-sorted-array/mmyeon.ts deleted file mode 100644 index 895c6f65f..000000000 --- a/find-minimum-in-rotated-sorted-array/mmyeon.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @link https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/ - * - * 접근 방법 : - * - O(logn)으로 풀어야 하니까 이진 탐색 적용 - * - 배열의 start, end 인덱스를 활용해서 최소값이 있는 방향을 탐색 - * - nums[mid] > nums[end]이면, 최소값이 오른쪽에 있으니까 start를 mid+1로 이동 - * - 반대로 nums[mid] < nums[end] 이면, 최소값이 왼쪽에 있으니까 end를 mid로 이동 - * - * 시간복잡도 : O(logn) - * - 탐색 범위를 계속 절반으로 줄이니까 O(logn) - * - * 공간복잡도 : O(1) - * - 고정된 변수만 사용 - */ -function findMin(nums: number[]): number { - let start = 0, - end = nums.length - 1; - - while (start < end) { - let mid = Math.floor(start + (end - start) / 2); - - if (nums[mid] > nums[end]) start = mid + 1; - else end = mid; - } - - return nums[start]; -} diff --git a/find-minimum-in-rotated-sorted-array/pmjuu.py b/find-minimum-in-rotated-sorted-array/pmjuu.py deleted file mode 100644 index 532b575e4..000000000 --- a/find-minimum-in-rotated-sorted-array/pmjuu.py +++ /dev/null @@ -1,22 +0,0 @@ -''' -시간 복잡도: O(log n) -- 이진 탐색을 사용하여 매 반복마다 검색 범위를 절반으로 줄이므로 O(log n)입니다. - -공간 복잡도: O(1) -- 추가적인 배열이나 리스트를 사용하지 않고, 몇 개의 변수만 사용하므로 O(1)입니다. -''' - -from typing import List - -class Solution: - def findMin(self, nums: List[int]) -> int: - left, right = 0, len(nums) - 1 - - while left < right: - mid = (left + right) // 2 - if nums[mid] > nums[right]: - left = mid + 1 # 최소값이 오른쪽에 있음 - else: - right = mid # 최소값이 mid 또는 왼쪽에 있음 - - return nums[left] diff --git a/find-minimum-in-rotated-sorted-array/yolophg.py b/find-minimum-in-rotated-sorted-array/yolophg.py deleted file mode 100644 index 3fb18de13..000000000 --- a/find-minimum-in-rotated-sorted-array/yolophg.py +++ /dev/null @@ -1,22 +0,0 @@ -# Time Complexity: O(log n) - using binary search, so cut the search space in half each time. -# Space Complexity: O(1) - only use a few variables (low, high, mid), no extra space. - -class Solution: - def findMin(self, nums: List[int]) -> int: - low = 0 - # start with the full range of the array - high = len(nums) - 1 - - # find the middle index - while low < high: - mid = low + (high - low) // 2 - - # if mid is greater than the last element, the min must be on the right - if nums[mid] > nums[high]: - # move the low pointer to the right - low = mid + 1 - else: - # min could be mid or in the left part - high = mid - # low and high converge to the minimum element - return nums[low] diff --git a/linked-list-cycle/Chaedie.py b/linked-list-cycle/Chaedie.py deleted file mode 100644 index 726834bc2..000000000 --- a/linked-list-cycle/Chaedie.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Solution: - 1) 사이클이 있다면 무한 루프가 발생할것이다. - 2) 사이클이 없다면 언젠가 null 이 될것이다. - 3) 따라서 두개의 포인터를 사용하여 동일한 Node에 도달하는 지 확인한다. - 4) null 이 된다면 사이클이 없다는 뜻이다. -Time: O(n) -Space: O(1) -""" - - -class Solution: - def hasCycle(self, head: Optional[ListNode]) -> bool: - if not head or not head.next: - return False - - slow = head - fast = head.next - while slow and fast and fast.next: - slow = slow.next - fast = fast.next.next - if slow == fast: - return True - return False diff --git a/linked-list-cycle/EcoFriendlyAppleSu.kt b/linked-list-cycle/EcoFriendlyAppleSu.kt deleted file mode 100644 index cf8858049..000000000 --- a/linked-list-cycle/EcoFriendlyAppleSu.kt +++ /dev/null @@ -1,21 +0,0 @@ -package leetcode_study - -/* -* 링크드 리스트에서 순환이 발생하는지 체크하는 문제 -* Node `val` 값을 주어진 범위 (-10,000 <= `val` <= 10,000) 보다 큰 정수로 변경해 cycle 판별 시도 -* 시간 복잡도: O(n) -* -> linked list node 개수만큼 진행 -* 공간 복잡도: O(1) -* -> 주어진 node를 가리키는 currentNode 이외에 추가되는 없음 -* */ -fun hasCycle(head: ListNode?): Boolean { - var currentNode = head - - while (currentNode?.next != null) { - if (currentNode.`val` == 10001) return true // 이미 방문한 노드이면 사이클 존재 - currentNode.`val` = 10001 // 방문한 노드 표시 - currentNode = currentNode.next // 다음 노드로 이동 - } - - return false // `null`을 만났다면 사이클 없음 -} diff --git a/linked-list-cycle/Jeehay28.js b/linked-list-cycle/Jeehay28.js deleted file mode 100644 index e6c143581..000000000 --- a/linked-list-cycle/Jeehay28.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ - -/** - * @param {ListNode} head - * @return {boolean} - */ - -// Time Complexity: O(n) -// Space Complexity: O(1) - -// - In the worst case, we might traverse the entire linked list, but because the fast pointer moves at twice the speed of the slow pointer, they will meet within O(N) steps if a cycle exists. -// - If there is no cycle, the fast pointer reaches the end in O(N) steps. -// - Only two pointers (slow and fast) are used, which require O(1) extra space. -// - No additional data structures (like arrays or hash sets) are used. - -var hasCycle = function (head) { - // If there is a cycle in the linked list, Floyd's Tortoise and Hare algorithm guarantees - // that the fast and slow pointers will eventually meet. - let fast = head; - let slow = head; - - while (fast && fast.next) { - slow = slow.next; // Move slow pointer one step. - fast = fast.next.next; // Move fast pointer two steps. - - if (slow === fast) { - return true; // Cycle detected. - } - } - - return false; -}; - diff --git a/linked-list-cycle/YeomChaeeun.ts b/linked-list-cycle/YeomChaeeun.ts deleted file mode 100644 index 3aca4c0d2..000000000 --- a/linked-list-cycle/YeomChaeeun.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Definition for singly-linked list. - * class ListNode { - * val: number - * next: ListNode | null - * constructor(val?: number, next?: ListNode | null) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - * } - */ -/** - * 순환되는 링크드 리스트 찾기 - * 알고리즘 복잡도 - * - 시간 복잡도: O(n) - * - 공간 복잡도: O(1) - * @param head - */ -function hasCycle(head: ListNode | null): boolean { - // 1. set을 이용한 풀이 - // 시간 복잡도: O(n) , 공간 복잡도: O(n) - // let set = new Set(); - // while(head !== null) { - // // set에 이미 존재하는지 확인 - // if(set.has(head)) return true - // set.add(head) - // head = head.next - // } - - // 2. 토끼와 거북이 알고리즘 - // 포인터를 2개 이동하는 방법 - let slow = head - let fast = head - - while (fast?.next) { - slow = slow.next - fast = fast.next.next - - if(slow === fast) { - return true - } - } - - return false -} diff --git a/linked-list-cycle/bus710.go b/linked-list-cycle/bus710.go deleted file mode 100644 index 6da1577cb..000000000 --- a/linked-list-cycle/bus710.go +++ /dev/null @@ -1,94 +0,0 @@ -package hello - -import "testing" - -type ListNode struct { - Val int - Next *ListNode -} - -// // Version 1 -// func hasCycle(head *ListNode) bool { -// if head == nil { -// return false -// } -// return call(head, make(map[*ListNode]int, 0)) -// } -// -// func call(h *ListNode, m map[*ListNode]int) bool { -// if h.Next == nil { -// return false -// } -// if _, ok := m[h]; ok { -// return true -// } -// m[h] = 1 -// return call(h.Next, m) -// } - -// Version 2 -func hasCycle(head *ListNode) bool { - if head == nil { - return false - } - m := map[*ListNode]int{} - for head.Next != nil { - if _, ok := m[head]; !ok { - m[head] = 1 - } else { - return true - } - head = head.Next - } - return false -} - -func Test_hasCycle(t *testing.T) { - // Case 0 list - c0_3 := &ListNode{Val: -4} - c0_2 := &ListNode{Val: 0, Next: c0_3} - c0_1 := &ListNode{Val: 2, Next: c0_2} - c0_0 := &ListNode{Val: 3, Next: c0_1} - c0_3.Next = c0_1 - - // Case 1 list - c1_1 := &ListNode{Val: 2} - c1_0 := &ListNode{Val: 1, Next: c1_1} - c1_1.Next = c1_0 - - // Case 2 list - c2_0 := &ListNode{Val: 1} - - type args struct { - head *ListNode - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "case 0", - args: args{head: c0_0}, - want: true, - }, - { - name: "case 1", - args: args{head: c1_0}, - want: true, - }, - { - name: "case 2", - args: args{head: c2_0}, - want: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := hasCycle(tt.args.head) - if got != tt.want { - t.Errorf("hasCycle() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/linked-list-cycle/dusunax.py b/linked-list-cycle/dusunax.py deleted file mode 100644 index 333647c84..000000000 --- a/linked-list-cycle/dusunax.py +++ /dev/null @@ -1,33 +0,0 @@ -''' -# 141. Linked List Cycle - -use two pointers, Floyd's Tortoise and Hare algorithm - -> Tortoise and Hare algorithm ->- slow pointer moves one step at a time ->- fast pointer moves two steps at a time ->- if there is a cycle, slow and fast will meet at some point ->- if there is no cycle, fast will reach the end of the list - -## Time Complexity: O(n) -In the worst case, we need to traverse the entire list to determine if there is a cycle. - -## Space Complexity: O(1) -no extra space is used, only the two pointers. -''' -class Solution: - def hasCycle(self, head: Optional[ListNode]) -> bool: - if not head or not head.next: - return False - - slow = head - fast = head - - while fast and fast.next: - slow = slow.next - fast = fast.next.next - - if slow == fast: - return True - - return False diff --git a/linked-list-cycle/ekgns33.java b/linked-list-cycle/ekgns33.java deleted file mode 100644 index 8e9aa79c7..000000000 --- a/linked-list-cycle/ekgns33.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Definition for singly-linked list. - * class ListNode { - * int val; - * ListNode next; - * ListNode(int x) { - * val = x; - * next = null; - * } - * } - */ - -/* -* input : singly linked list and head node -* output : return true if list has cycle -* -* solution : tortoise and hare algorithm -* with two pointer (slow and fast) -* tc : O(n) -* sc : O(1) -* -* */ -public class Solution { - public boolean hasCycle(ListNode head) { - if(head == null) return false; - ListNode slow = head; - ListNode fast = head; - while(fast.next != null && fast.next.next != null) { - slow = slow.next; - fast = fast.next.next; - if(fast == slow) return true; - } - return false; - } -} diff --git a/linked-list-cycle/eunhwa99.java b/linked-list-cycle/eunhwa99.java deleted file mode 100644 index aeae66cd0..000000000 --- a/linked-list-cycle/eunhwa99.java +++ /dev/null @@ -1,36 +0,0 @@ - -class ListNode { - - int val; - ListNode next; - - ListNode(int x) { - val = x; - next = null; - } -} - -public class Solution { - - // Floyd's Tortoise and Hare Algorithm - // TC: O(N) - // SC: O(1) - public boolean hasCycle(ListNode head) { - if (head == null || head.next == null) { - return false; - } - - ListNode slow = head; - ListNode fast = head; - - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - - if (slow == fast) { - return true; - } - } - return false; - } -} diff --git a/linked-list-cycle/forest000014.java b/linked-list-cycle/forest000014.java deleted file mode 100644 index 57b672067..000000000 --- a/linked-list-cycle/forest000014.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - # Time Complexity : O(n) - # Space Complexity: O(1) - - * Definition for singly-linked list. - * class ListNode { - * int val; - * ListNode next; - * ListNode(int x) { - * val = x; - * next = null; - * } - * } - */ -public class Solution { - private final int VISITED = -999999; - public boolean hasCycle(ListNode head) { - while (head != null) { - if (head.val == VISITED) { - return true; - } - - head.val = VISITED; - head = head.next; - } - - return false; - } -} diff --git a/linked-list-cycle/gmlwls96.kt b/linked-list-cycle/gmlwls96.kt deleted file mode 100644 index 76e444ef4..000000000 --- a/linked-list-cycle/gmlwls96.kt +++ /dev/null @@ -1,16 +0,0 @@ -class Solution { - // 시간 : O(n) - // 세트에 head.val 값을 추가하면서 동일한 값이 있는지 체크. 동일한 값이 존재하면 순회한다고 판단. - fun hasCycle(head: ListNode?): Boolean { - val set = mutableSetOf() - var next = head - while (next != null) { - if (set.contains(next.`val`)) { - return true - } - set.add(next.`val`) - next = next.next - } - return false - } -} diff --git a/linked-list-cycle/limlimjo.js b/linked-list-cycle/limlimjo.js deleted file mode 100644 index 2ea96537b..000000000 --- a/linked-list-cycle/limlimjo.js +++ /dev/null @@ -1,29 +0,0 @@ -// 시간 복잡도: O(n) -// 공간 복잡도: O(1) -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ - -/** - * @param {ListNode} head - * @return {boolean} - */ -var hasCycle = function (head) { - let slow = head; - let fast = head; - - while (fast !== null && fast.next !== null) { - slow = slow.next; - fast = fast.next.next; - - if (slow === fast) { - return true; - } - } - - return false; -}; diff --git a/linked-list-cycle/mike2ox.ts b/linked-list-cycle/mike2ox.ts deleted file mode 100644 index bf4ac00f2..000000000 --- a/linked-list-cycle/mike2ox.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Source: https://leetcode.com/problems/linked-list-cycle/ - * 풀이방법: Set을 이용하여 방문한 노드를 저장하고 순회하면서 중복된 노드가 있는지 확인 - * - * 시간복잡도: O(n) - * 공간복잡도: O(n) - */ - -// class ListNode { -// val: number; -// next: ListNode | null; -// constructor(val?: number, next?: ListNode | null) { -// this.val = val === undefined ? 0 : val; -// this.next = next === undefined ? null : next; -// } -// } - -function hasCycle(head: ListNode | null): boolean { - if (head === null) return false; - - // 방문한 노드들을 저장할 Set - const addr = new Set(); - - // 첫 노드 추가 - addr.add(head); - head = head.next; - - // 리스트 순회 - while (head !== null) { - // 이미 방문한 노드인 경우 cycle 존재 - if (addr.has(head)) return true; - - // 새로운 노드 추가 - addr.add(head); - head = head.next; - } - - return false; -} diff --git a/linked-list-cycle/mintheon.java b/linked-list-cycle/mintheon.java deleted file mode 100644 index feb7a1899..000000000 --- a/linked-list-cycle/mintheon.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Definition for singly-linked list. - * class ListNode { - * int val; - * ListNode next; - * ListNode(int x) { - * val = x; - * next = null; - * } - * } - */ -//시간복잡도: O(n) -//공간복잡도: O(1) -public class Solution { - public boolean hasCycle(ListNode head) { - ListNode slow = head; - ListNode fast = head; - - while(fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - - if(slow == fast) return true; - } - - return false; - } -} diff --git a/linked-list-cycle/mmyeon.ts b/linked-list-cycle/mmyeon.ts deleted file mode 100644 index 2f9236925..000000000 --- a/linked-list-cycle/mmyeon.ts +++ /dev/null @@ -1,61 +0,0 @@ -class ListNode { - val: number; - next: ListNode | null; - constructor(val?: number, next?: ListNode | null) { - this.val = val === undefined ? 0 : val; - this.next = next === undefined ? null : next; - } -} - -/** - * @link https://leetcode.com/problems/linked-list-cycle/description/ - * - * 접근 방법 : - * - 노드 순회하면서 방문한 노드에 저장 - * - 방문할 노드가 이미 방문한 노드에 있으면 순환 구조 이므로 true 리턴 - * - * 시간복잡도 : O(n) - * - 순환 이전 노드의 개수 n만큼 순회하면서 순환 여부 확인 - * - * 공간복잡도 : O(n) - * - visited set에 순환되기 이전 노드 n개 저장 - */ -function hasCycle(head: ListNode | null): boolean { - const visited = new Set(); - let current = head; - - while (current !== null) { - if (visited.has(current)) return true; - - visited.add(current); - current = current.next; - } - - return false; -} - -/* - * 접근 방법 : - * - 공간복잡도 O(1)로 풀이 - * - 사이클이 있으면 두 포인터가 결국 같은 노드를 가리키게 되므로 투 포인터 사용 - * - 사이클이 없는 경우를 위해서 tail노드의 null체크를 해야함 - * - * 시간복잡도 : O(n) - * - 순환 이전 노드의 개수 n만큼 순회하면서 순환 여부 확인 - * - * 공간복잡도 : O(1) - * - 추가 메모리없이 slow, fast 포인터만 사용하므로 O(1) - */ -function hasCycle(head: ListNode | null): boolean { - let slow = head; - let fast = head; - - while (fast !== null && fast.next !== null) { - slow = slow.next; - fast = fast.next.next; - - if (slow === fast) return true; - } - - return false; -} diff --git a/linked-list-cycle/pmjuu.py b/linked-list-cycle/pmjuu.py deleted file mode 100644 index 0f1d818e1..000000000 --- a/linked-list-cycle/pmjuu.py +++ /dev/null @@ -1,28 +0,0 @@ -''' -시간 복잡도: O(n) -- `fast`와 `slow` 포인터가 리스트를 한 번 순회하면서 주어진 연결 리스트의 길이에 비례하는 작업을 수행합니다. -- 따라서 최악의 경우 모든 노드를 한 번씩 방문하게 되므로 O(n)입니다. - -공간 복잡도: O(1) -- 추가적인 자료구조를 사용하지 않고, `fast`와 `slow`라는 두 개의 포인터만 사용하므로 O(1)입니다. -''' -from typing import Optional -# Definition for singly-linked list. -class ListNode: - def __init__(self, x): - self.val = x - self.next = None - -class Solution: - def hasCycle(self, head: Optional[ListNode]) -> bool: - fast = head - slow = head - - while fast and fast.next: - fast = fast.next.next - slow = slow.next - - if fast == slow: - return True - - return False diff --git a/linked-list-cycle/yolophg.py b/linked-list-cycle/yolophg.py deleted file mode 100644 index 4d8f9a8f3..000000000 --- a/linked-list-cycle/yolophg.py +++ /dev/null @@ -1,21 +0,0 @@ -# Time Complexity: O(n) - traverse the linked list at most once. -# Space Complexity: O(1) - only use two pointers, no extra memory. - -class Solution: - def hasCycle(self, head: Optional[ListNode]) -> bool: - # two pointers for fast moves twice as fast as slow. - fast = head - slow = head - - # loop the list while fast and fast.next exist. - while fast and fast.next: - # move fast pointer two steps. - fast = fast.next.next - # move slow pointer one step. - slow = slow.next - - # if they meet, there's a cycle. - if fast == slow: - return True - # if they don't meet, there's no cycle. - return False diff --git a/longest-common-subsequence/EcoFriendlyAppleSu.kt b/longest-common-subsequence/EcoFriendlyAppleSu.kt deleted file mode 100644 index da02e95e9..000000000 --- a/longest-common-subsequence/EcoFriendlyAppleSu.kt +++ /dev/null @@ -1,63 +0,0 @@ -package leetcode_study - -/* -* 가장 긴 공통 부분 문자열의 길이를 구하는 문제 -* 동적 계획법을 사용한 문제 해결 -* 문자가 동일할 경우, table[i][j] = table[i-1][j-1] + 1. 즉, 이전까지의 최장 공통 부분 문자열 길이에 1을 추가 -* 문자가 다를 경우, table[i][j] = max(table[i-1][j], table[i][j-1]) 이는 현재까지 찾은 최장 공통 부분 문자열의 길이를 유지하는 과정 -* -* 시간 복잡도: O(n^2) -* -> 두 분자열을 이중 반복을 진행하는 경우 -* 공간 복잡도: O(nm) (= n과 m은 각각 주어진 문자열을 길이) -* -> dp table에 사용되는 공간 -* */ -fun longestCommonSubsequence(text1: String, text2: String): Int { - val n = text1.length - val m = text2.length - val dp = Array(n + 1) { IntArray(m + 1) } - - for (i in 1..n) { - for (j in 1..m) { - if (text1[i - 1] == text2[j - 1]) { - dp[i][j] = dp[i - 1][j - 1] + 1 - } else { - dp[i][j] = maxOf(dp[i - 1][j], dp[i][j - 1]) - } - } - } - return dp[n][m] -} - -/* -* 주어진 두 문자열에 각각의 Index를 두어 비교해가며 해결 시도 해당 방법으로 시도 -* Test case를 통과했지만 "bac", "abc"와 같은 case에서 "bc"를 답으로 도출할 수 있지만 "ac"와 같은 경우는 지나치게됨 -* 즉, 정답이 되는 경우를 제외할 수 있음. -* */ -fun longestCommonSubsequence(text1: String, text2: String): Int { - var result = 0 - var longOne: String - var shortOne: String - var longIndex = 0 - var shortIndex = 0 - - if (text1.length >= text2.length) { - longOne = text1 - shortOne = text2 - } else { - longOne = text2 - shortOne = text1 - } - - while (shortIndex < shortOne.length) { - if (shortOne[shortIndex] == longOne[longIndex]) { - shortIndex += 1 - longIndex += 1 - result += 1 - } else { - longIndex += 1 - } - if (longIndex == longOne.length) break - } - - return result -} diff --git a/longest-substring-without-repeating-characters/gmlwls96.kt b/longest-substring-without-repeating-characters/gmlwls96.kt new file mode 100644 index 000000000..33808e5cc --- /dev/null +++ b/longest-substring-without-repeating-characters/gmlwls96.kt @@ -0,0 +1,16 @@ +class Solution { + // 시간 : O(n) 공간 : O(n) + fun lengthOfLongestSubstring(s: String): Int { + var max = 0 + val subStr = StringBuffer() + s.forEach { // s를 조회하면서 글자를 subStr에 담는다. + if (subStr.contains(it)) { // 단, 겹치는 글자가 있을경우 subStr의 len을 기록하고, 초기화 한다. + max = max(max, subStr.length) + subStr.delete(0, subStr.length) + } + subStr.append(it) + } + max = max(max, subStr.length) + return max + } +} diff --git a/maximum-product-subarray/Chaedie.py b/maximum-product-subarray/Chaedie.py deleted file mode 100644 index bd0172bee..000000000 --- a/maximum-product-subarray/Chaedie.py +++ /dev/null @@ -1,37 +0,0 @@ -class Solution: - """ - Brute Force - - Time: O(n^2) - Space: O(1) - """ - - def maxProduct(self, nums: List[int]) -> int: - - max_prod = float(-inf) - for i in range(len(nums)): - prod = nums[i] - max_prod = max(max_prod, prod) - for j in range(i + 1, len(nums)): - prod *= nums[j] - max_prod = max(max_prod, prod) - - return max_prod - - """ - 최소곱, 최대곱을 모두 저장하면서 최대값을 찾는다. - (음수 곱 양수곱을 모두 커버하기 위해 최소곱도 저장한다.) - - Time: O(n) - Space: O(1) - """ - - def maxProduct(self, nums: List[int]) -> int: - result = nums[0] - min_prod, max_prod = 1, 1 - for num in nums: - arr = [min_prod * num, max_prod * num, num] - min_prod = min(arr) - max_prod = max(arr) - result = max(max_prod, result) - return result diff --git a/maximum-product-subarray/Jeehay28.js b/maximum-product-subarray/Jeehay28.js deleted file mode 100644 index fa02f9a83..000000000 --- a/maximum-product-subarray/Jeehay28.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @param {number[]} nums - * @return {number} - */ - -// ✅ DP approach -// Time Complexity: O(n) -// Space Complexity: O(1) -var maxProduct = function (nums) { - // Track the minimum and maximum product ending at the current position - // Consider three possibilities for each element: - // 1. Current number - // 2. Previous min product * current number (to handle negative numbers) - // 3. Previous max product * current number (to handle negative numbers) - - let maxProduct = nums[0]; - let previousMinProduct = 1; - let previousMaxProduct = 1; - - for (const current of nums) { - const temp1 = previousMinProduct * current; - const temp2 = previousMaxProduct * current; - - // Update min and max product - previousMinProduct = Math.min(current, temp1, temp2); - previousMaxProduct = Math.max(current, temp1, temp2); - - // Update maxProduct - maxProduct = Math.max(maxProduct, previousMaxProduct); - } - - return maxProduct; -}; - -// 🤔 more efficient than the previous one, but there might be a further optimization -// using dynamic programming approach to reduce the complexity to O(n) -// Time Complexity: O(n^2) -// Space Complexity: O(1) - -// var maxProduct = function (nums) { -// let max = nums[0]; - -// for (let s = 0; s < nums.length; s++) { -// let temp = 1; -// for (let e = s; e < nums.length; e++) { -// temp *= nums[e]; -// max = Math.max(max, temp); -// } -// } -// return max; -// }; - -// 😱 Time Limit Exceeded! -// Time Complexity: O(n^3) -// Space Complexity: O(1) -// var maxProduct = function (nums) { -// let max = nums[0]; - -// for (let s = 0; s < nums.length; s++) { -// for (let e = s; e < nums.length; e++) { -// let temp = 1; - -// for (let i = s; i <= e; i++) { -// temp *= nums[i]; -// } - -// max = Math.max(max, temp); -// } -// } - -// return max; -// }; - - diff --git a/maximum-product-subarray/YeomChaeeun.ts b/maximum-product-subarray/YeomChaeeun.ts deleted file mode 100644 index 06a9b8431..000000000 --- a/maximum-product-subarray/YeomChaeeun.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * 최대 부분 곱 구하기 - * 알고리즘 복잡도 - * - 시간 복잡도: O(n) - * - 공간 복잡도: O(1) - * @param nums - */ -function maxProduct(nums: number[]): number { - if(nums.length === 1) return nums[0] - - let max = nums[0] - let currMax = nums[0] - let currMin = nums[0] - - for(let i = 1; i < nums.length; i++) { - const temp = currMax; - - currMax = Math.max( - nums[i], temp * nums[i], currMin * nums[i] - ) - - currMin = Math.min( - nums[i], temp * nums[i], currMin * nums[i] - ) - - max = Math.max(max, currMax); - } - - return max; - -} diff --git a/maximum-product-subarray/dusunax.py b/maximum-product-subarray/dusunax.py deleted file mode 100644 index e2f796ce8..000000000 --- a/maximum-product-subarray/dusunax.py +++ /dev/null @@ -1,31 +0,0 @@ -''' -# 152. Maximum Product Subarray - -solution reference: https://www.algodale.com/problems/maximum-product-subarray/ - -## 최대 곱 배열 구하기 -- 연속 배열(subarray)에 양수, 음수, 0이 포함될 수 있다. -- 음수가 결과에 영향을 미칠 수 있기 때문에 최소값/최대값 추적이 필요하다. - -## 값 -- result: 최종적으로 반환할 값 -- min_prod: 현재까지의 최소 곱 값 (음수를 고려한 추적) -- max_prod: 현재까지의 최대 곱 값 - -## 새로운 값 num이 주어졌을 때 -- 새로운 배열을 시작할 지, 기존 배열에 추가할 지 결정 -- 후보들로 최대값의 가능성을 확인하고 result를 업데이트한다. -''' -class Solution: - def maxProduct(self, nums: List[int]) -> int: - result = nums[0] - min_prod = 1 - max_prod = 1 - - for num in nums: - candidates = (min_prod * num, max_prod * num, num) - min_prod = min(candidates) - max_prod = max(candidates) - result = max(max_prod, result) - - return result diff --git a/maximum-product-subarray/ekgns33.java b/maximum-product-subarray/ekgns33.java deleted file mode 100644 index bc101bfc3..000000000 --- a/maximum-product-subarray/ekgns33.java +++ /dev/null @@ -1,45 +0,0 @@ -class Solution { - public int maxProduct(int[] nums) { - int n = nums.length; - int[][] product = new int[2][n]; - product[0][0] = nums[0]; - product[1][0] = nums[0]; - int max = nums[0]; - for(int i = 1; i < n; i++) { - product[0][i] = Math.max(product[0][i-1]*nums[i], Math.max(nums[i], nums[i] * product[1][i-1])); - product[1][i] = Math.min(product[0][i-1]*nums[i], Math.min(nums[i], nums[i] * product[1][i-1])); - max =Math.max(max, product[0][i]); - } - return max; - } -} -/** - - - brute force : - nested for loop - tc : O(n^2) - sc : O(1) - - better sol : - maintain min and max - tc : O(n) - sc : O(n) - - compare with prev Min * cur, prevMax * cur, cur - we have to keep track of minimum value that can lead to maximum value - when there are negative values later. - - 2 3 -2 4 - 2 6 -2 4 - 2 2 -12 -48 - - -2 0 -1 - -2 0 0 - -2 0 -1 - - 2 3 -2 5 7 -100 - 2 6 -2 5 35 210000 - 2 3 -6 -30 -210. -35 - - */ diff --git a/maximum-product-subarray/eunhwa99.java b/maximum-product-subarray/eunhwa99.java deleted file mode 100644 index 36bacb7a0..000000000 --- a/maximum-product-subarray/eunhwa99.java +++ /dev/null @@ -1,26 +0,0 @@ -class Solution { - - // TP: O(N) - // SP: O(1) - // 음수 원소를 처리하기 위해 곱의 Min 값도 생각해야 했던 문제! - public int maxProduct(int[] nums) { - - int minProd = nums[0]; - int maxProd = nums[0]; - int result = nums[0]; - for (int i = 1; i < nums.length; i++) { - if (nums[i] < 0) { - int temp = minProd; - minProd = maxProd; - maxProd = temp; - } - - maxProd = Math.max(nums[i], maxProd * nums[i]); - minProd = Math.min(nums[i], minProd * nums[i]); - result = Math.max(result, maxProd); - } - - return result; - } -} - diff --git a/maximum-product-subarray/forest000014.java b/maximum-product-subarray/forest000014.java deleted file mode 100644 index db31e28c1..000000000 --- a/maximum-product-subarray/forest000014.java +++ /dev/null @@ -1,89 +0,0 @@ -/* -# Time Complexity: O(n) - -# Space Complexity: O(1) - -# Solution -1. array에 0이 존재하는 경우 - -(observation: 정답이 음수가 될 가능성이 있는가? Yes. 다만, 원소 개수가 1개이고, 그 원소가 음수인 경우에만 그렇다. 음수인 원소가 2개 이상인 경우는 subarray를 잘 선택하면 그 곱을 항상 0 이상으로 만들 수 있다. 즉, 원소 개수가 1개이고 음수인 경우만 예외 처리를 해주면, 그 외의 경우는 정답이 0이거나 양수이다.) - -subarray에 0이 포함되는 순간 곱은 0이 되므로, 0보다 큰 곱을 찾기 위해서는 0을 제외하고 판단한다. -즉, 0을 기준으로 slice해서, 각각의 segment만 독립적으로 검토하면 된다. (0으로 slice한 각 segment가 아래 2번 케이스로 환원된다.) - -2. (sub)array에 0이 존재하지 않는 경우 -음수의 개수에 따라 접근을 다르게 한다. - -2-1. 짝수개 -고민할 것 없이, 전체 subarray의 원소를 곱하면 그 subarray에서 얻을 수 있는 곱의 최대값이다. - -2-2. 홀수개 -subarray 양 끝에서 각각 출발하여 최초의 마이너스(즉 가장 바깥쪽의 마이너스)를 만날 때까지, 원소들을 누적해서 곱하며 이동. -두 값 중 절대값이 작은 쪽을 subarray에서 제외. 남은 부분의 곱을 구하면, 최대값이다. -*/ - -class Solution { - public int maxProduct(int[] nums) { - if (nums.length == 1) { - return nums[0]; - } - - int ans = 0; - int start = 0; - for (int i = 0; i < nums.length; i++) { - if (nums[i] != 0) { - continue; - } - - if (i > 0) { - int res = calculateMaxProduct(start, i - 1, nums); - ans = Math.max(ans, res); - } - start = i + 1; - } - - if (start <= nums.length - 1) { - int res = calculateMaxProduct(start, nums.length - 1, nums); - ans = Math.max(ans, res); - } - - return ans; - } - - private int calculateMaxProduct(int l, int r, int[] nums) { - if (l == r) { - return nums[l]; - } - - int minusCount = 0; - int product = 1; - for (int i = l; i <= r; i++) { - if (nums[i] < 0) { - minusCount++; - } - product *= nums[i]; - } - - if (minusCount % 2 == 0) { - return product; - } else { - int leftProduct = 1; - for (int i = l; i <= r; i++) { - leftProduct *= nums[i]; - if (nums[i] < 0) { - break; - } - } - - int rightProduct = 1; - for (int i = r; i >= l; i--) { - rightProduct *= nums[i]; - if (nums[i] < 0) { - break; - } - } - - return product / Math.max(leftProduct, rightProduct); - } - } -} diff --git a/maximum-product-subarray/gmlwls96.kt b/maximum-product-subarray/gmlwls96.kt deleted file mode 100644 index 45f7c28e0..000000000 --- a/maximum-product-subarray/gmlwls96.kt +++ /dev/null @@ -1,15 +0,0 @@ -class Solution { - fun maxProduct(nums: IntArray): Int { - var max = 1 - var min = 1 - var result = nums[0] - nums.forEach { num -> - val v1 = min * num - val v2 = max * num - min = min(min(v1, v2), num) - max = max(max(v1, v2), num) - result = max(max, result) - } - return result - } -} diff --git a/maximum-product-subarray/mike2ox.ts b/maximum-product-subarray/mike2ox.ts deleted file mode 100644 index 886318a46..000000000 --- a/maximum-product-subarray/mike2ox.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Source: https://leetcode.com/problems/maximum-product-subarray/ - * 풀이방법: 현재 곱과 최대 곱을 비교하여 최대값을 구함 - * - * 시간복잡도: O(n) - * 공간복잡도: O(1) - * - * 다른 풀이방법 - * - DP를 이용하여 풀이 - */ -function maxProduct(nums: number[]): number { - if (nums.length === 0) return 0; - - let maxProduct = nums[0]; - let currentProduct = 1; - - // 왼쪽에서 오른쪽으로 순회 - for (let i = 0; i < nums.length; i++) { - currentProduct *= nums[i]; - maxProduct = Math.max(maxProduct, currentProduct); - // 현재 곱이 0이 되면 리셋 - if (currentProduct === 0) { - currentProduct = 1; - } - } - - currentProduct = 1; - - // 오른쪽에서 왼쪽으로 순회 - for (let i = nums.length - 1; i >= 0; i--) { - currentProduct *= nums[i]; - maxProduct = Math.max(maxProduct, currentProduct); - // 현재 곱이 0이 되면 리셋 - if (currentProduct === 0) { - currentProduct = 1; - } - } - - return maxProduct; -} diff --git a/maximum-product-subarray/mintheon.java b/maximum-product-subarray/mintheon.java deleted file mode 100644 index d6cdc86c9..000000000 --- a/maximum-product-subarray/mintheon.java +++ /dev/null @@ -1,26 +0,0 @@ -class Solution { - //시간복잡도: O(n) - //공간복잡도: O(n) - public int maxProduct(int[] nums) { - int[] maxValue = new int[nums.length]; - int[] minValue = new int[nums.length]; - - maxValue[0] = nums[0]; - minValue[0] = nums[0]; - - for(int i = 1; i < nums.length; i++) { - int value1 = maxValue[i - 1] * nums[i]; - int value2 = minValue[i - 1] * nums[i]; - - maxValue[i] = Math.max(Math.max(value1, value2), nums[i]); - minValue[i] = Math.min(Math.min(value1, value2), nums[i]); - } - - int result = Integer.MIN_VALUE; - for(int i = 0; i < nums.length; i++) { - result = Math.max(result, maxValue[i]); - } - - return result; - } -} diff --git a/maximum-product-subarray/mmyeon.ts b/maximum-product-subarray/mmyeon.ts deleted file mode 100644 index 1f44842cb..000000000 --- a/maximum-product-subarray/mmyeon.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @link https://leetcode.com/problems/maximum-product-subarray/ - * - * 접근 방법 : - * - 음수가 짝수번 나오면 최대값이 될 수 있으니까 최소곱, 최대곱을 모두 업데이트 - * - 현재 값이 단독으로 최소, 최대일 수 있으니까 현재값, 최소곱 * 현재값, 최대곱 * 현재값을 비교 - * - * 시간복잡도 : O(n) - * - nums 1회 순회 - * - * 공간복잡도 : O(1) - * - 고정된 변수만 사용 - */ -function maxProduct(nums: number[]): number { - let currentMin = nums[0], - currentMax = nums[0], - maxSoFar = nums[0]; - - for (let i = 1; i < nums.length; i++) { - const num = nums[i]; - const minCandidate = currentMin * num; - const maxCandidate = currentMax * num; - - currentMin = Math.min(num, minCandidate, maxCandidate); - currentMax = Math.max(num, minCandidate, maxCandidate); - - maxSoFar = Math.max(currentMax, maxSoFar); - } - - return maxSoFar; -} diff --git a/maximum-product-subarray/pmjuu.py b/maximum-product-subarray/pmjuu.py deleted file mode 100644 index 04a389fa1..000000000 --- a/maximum-product-subarray/pmjuu.py +++ /dev/null @@ -1,24 +0,0 @@ -''' -시간 복잡도: O(n) -- 리스트를 한 번 순회하면서 각 요소에 대해 최대값과 최소값을 갱신하므로 O(n)입니다. - -공간 복잡도: O(1) -- 추가적인 배열을 사용하지 않고, 몇 개의 변수만 사용하므로 O(1)입니다. -''' - -from typing import List - -class Solution: - def maxProduct(self, nums: List[int]) -> int: - n = len(nums) - max_product = nums[0] - cur_max = nums[0] # 현재 위치까지 최대 곱 - cur_min = nums[0] # 현재 위치까지 최소 곱 (음수 대비) - - for i in range(1, n): - temp_max = cur_max - cur_max = max(nums[i], cur_max * nums[i], cur_min * nums[i]) - cur_min = min(nums[i], temp_max * nums[i], cur_min * nums[i]) - max_product = max(max_product, cur_max) - - return max_product diff --git a/maximum-product-subarray/yolophg.py b/maximum-product-subarray/yolophg.py deleted file mode 100644 index c493c51a0..000000000 --- a/maximum-product-subarray/yolophg.py +++ /dev/null @@ -1,25 +0,0 @@ -# Time Complexity: O(N) - just one pass through the array, so it's linear time. -# Space Complexity: O(1) - no extra arrays, just a few variables. - -class Solution: - def maxProduct(self, nums: List[int]) -> int: - # tracking max product from both ends - prefix_product, suffix_product = 1, 1 - # start with the biggest single number - max_product = max(nums) - - for i in range(len(nums)): - # move forward, multiplying - prefix_product *= nums[i] - # move backward, multiplying - suffix_product *= nums[len(nums) - i - 1] - # update max product - max_product = max(max_product, prefix_product, suffix_product) - - # if hit zero, reset to 1 (zero kills the product chain) - if prefix_product == 0: - prefix_product = 1 - if suffix_product == 0: - suffix_product = 1 - - return max_product diff --git a/minimum-window-substring/Jeehay28.js b/minimum-window-substring/Jeehay28.js deleted file mode 100644 index 7a2c56638..000000000 --- a/minimum-window-substring/Jeehay28.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @param {string} s - * @param {string} t - * @return {string} - */ - -// 🚀 sliding window + two pointer approach - -// 🕒 Time Complexity: O(n), where n is the length of s -// The inner while loop shrinks the window from the left side but never exceeds the total number of characters in s - -// 🗂 Space Complexity: O(m) (or worst case O(n)), where n is the length of t - -var minWindow = function (s, t) { - // early return for the critical edge case - if (s.length < t.length) { - return ""; - } - - let windowCnt = new Map(); - let charCnt = new Map(); - let minStart = 0; - let minEnd = s.length; // set this to an out-of-bounds value initially - - let formed = 0; - let left = 0; - - // initialize charCount - // 🔢 t = "ABC", charCount = { A: 1, B: 1, C: 1 } - for (const ch of t) { - charCnt.set(ch, (charCnt.get(ch) || 0) + 1); - } - - // expand the windowCnt - for (let right = 0; right < s.length; right++) { - const char = s[right]; - - windowCnt.set(char, (windowCnt.get(char) || 0) + 1); - - if (charCnt.has(char) && charCnt.get(char) === windowCnt.get(char)) { - formed += 1; - } - - // shrink the window by moving the left pointer - while (formed === charCnt.size) { - if (right - left < minEnd - minStart) { - minStart = left; - minEnd = right; - } - - const char = s[left]; - windowCnt.set(char, windowCnt.get(char) - 1); - - if (charCnt.has(char) && windowCnt.get(char) < charCnt.get(char)) { - formed -= 1; - } - left += 1; - } - } - - return minEnd === s.length ? "" : s.slice(minStart, minEnd + 1); -}; - diff --git a/minimum-window-substring/dusunax.py b/minimum-window-substring/dusunax.py deleted file mode 100644 index b8d6fe66c..000000000 --- a/minimum-window-substring/dusunax.py +++ /dev/null @@ -1,68 +0,0 @@ -''' -# 76. Minimum Window Substring - -solution reference: https://www.algodale.com/problems/minimum-window-substring/ - -## 주어진 문자열 s에서 문자열 t의 모든 문자를 포함하는 최소 윈도우를 찾아 반환하기 🔥 - -> 슬라이딩 윈도우, 최소 윈도우 찾기, 문자열의 빈도 추적, t의 모든 문자가 현재 윈도우에 포함되어 있는지 추적 - -- 윈도우의 오른쪽 끝을 확장하면서, 필요한 모든 문자가 포함되었을 때, 윈도우의 크기를 최소화하기 - -## 값 -- counts: 필요한 문자가 몇 번 등장하는지 추적 -- n_included: 윈도우 안에서 t에 필요한 문자 개수 추적 -- low, high: 슬라이딩 윈도우의 양 끝 -- min_low max_high: 반환값, 슬라이딩 윈도우의 양 끝 - -## s 탐색 -- s의 오른쪽 끝을 탐색합니다. - - 현재 문자가 t에 존재한다면(counts에 키가 존재) - - 그리고 필요한 문자라면(값이 1 이상) - - 윈도우 내부의 필요 문자 개수를 하나 증가시킵니다. - - 해당 문자의 등장 count를 하나 감소시킵니다. - -## 윈도우 축소하기 -- 아래 문항을 필요한 값이 윈도우 안에 존재하는 동안 반복합니다. -1. 현재 구한 윈도우가 더 작은 지 확인하고, 작다면 반환할 윈도우를 업데이트 합니다. -2. s의 왼쪽 끝을 탐색합니다. - - 현재 문자가 t에 존재한다면(counts에 키가 존재) - - 해당 문자의 등장 count를 하나 증가시킵니다. - - 그리고 필요한 문자라면(값이 1 이상) - - 윈도우 내부의 필요 문자 개수를 하나 축소시킵니다.(반복문의 조건을 벗어납니다.) -3. 다음 탐색 전 왼쪽 위치를 하나 증가시킵니다. - -## 반환 -- 최소 윈도우의 시작과 끝을 low와 high + 1로 반환하되, 유효한 윈도우가 아니라면 ""을 반환합니다. -''' -class Solution: - def minWindow(self, s: str, t: str) -> str: - min_low = 0 - max_high = len(s) - counts = Counter(t) - n_included = 0 - - low = 0 - # s 탐색 - for high in range(len(s)): - char_high = s[high] - if char_high in counts: - if counts[char_high] > 0: - n_included += 1 - counts[char_high] -= 1 - - # 윈도우 축소하기 - while n_included == len(t): - if high - low < max_high - min_low: # 1 - min_low = low - max_high = high - - char_low = s[low] - if char_low in counts: # 2 - counts[char_low] += 1 - if counts[char_low] > 0: - n_included -= 1 - - low += 1 # 3 - - return s[min_low: max_high + 1] if max_high < len(s) else "" diff --git a/minimum-window-substring/ekgns33.java b/minimum-window-substring/ekgns33.java deleted file mode 100644 index 2557f8ef9..000000000 --- a/minimum-window-substring/ekgns33.java +++ /dev/null @@ -1,30 +0,0 @@ -class Solution { - public String minWindow(String s, String t) { - int[] freq = new int[128]; - char[] str = s.toCharArray(); - int minL = 0; - int minLength = Integer.MAX_VALUE; - int l = 0, r = 0, n = s.length(); - for(char c : t.toCharArray()) { - freq[c-'A']++; - } - int resolved = t.length(); - while(r < n) { - if(freq[str[r++] - 'A']-- > 0) { - resolved--; - } - while(resolved == 0) { - if(r - l < minLength) { - minL = l; - minLength = r - l; - } - if(freq[str[l] - 'A']++ == 0) { - resolved++; - } - l++; - } - } - if(minLength == Integer.MAX_VALUE) return ""; - return new String(str, minL, minLength); - } -} diff --git a/minimum-window-substring/gmlwls96.kt b/minimum-window-substring/gmlwls96.kt deleted file mode 100644 index 0f62c888e..000000000 --- a/minimum-window-substring/gmlwls96.kt +++ /dev/null @@ -1,32 +0,0 @@ -class Solution { - fun minWindow(s: String, t: String): String { - if (s.length < t.length) { - return "" - } - val containIndexList = mutableListOf() - for (i in s.indices) { - if (t.contains(s[i])) { - containIndexList.add(i) - } - } - var answer = "" - val regex = - t.toCharArray().joinToString(separator = "", prefix = "^", postfix = ".+$") { """(?=.*${it})""" }.toRegex() - for (i in 0..containIndexList.size - t.length) { - val startIndex = containIndexList[i] - for (l in t.length..containIndexList.size - i) { - val endIndex = containIndexList[(i + l) - 1] + 1 - val subStr = s.substring(startIndex, endIndex) - if (regex.containsMatchIn(subStr)) { - if (answer.isEmpty()) { - answer = subStr - } else if (subStr.length < answer.length) { - answer = subStr - } - break - } - } - } - return answer - } -} diff --git a/minimum-window-substring/mmyeon.ts b/minimum-window-substring/mmyeon.ts deleted file mode 100644 index 2cdcc27b4..000000000 --- a/minimum-window-substring/mmyeon.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @link https://leetcode.com/problems/minimum-window-substring/description/ - * 접근 방법 : 2개의 포인터 활용해서 슬라이딩 윈도우 방식 사용 - * - t의 문자를 맵에 저장해서 개수 기록 - * - right 포인터로 t의 모든 문자 포함할 때까지 윈도우 확장 - * - 모든 문자 포함하면, left 포인터로 최소 윈도우 찾을 때까지 윈도우 축소 - * - '확장 => 축소 => 최소 윈도우 업데이트' 이 과정을 반복 - * - * 시간복잡도 : O(n) - * - n은 s의 길이, 각 문자 최대 2회 방문 (확장 + 축소) - * - * 공간복잡도 : O(n) - * - 최악의 경우, 윈도우에 s의 모든 문자가 저장됨 - */ -function minWindow(s: string, t: string): string { - const targetCharCount = new Map(); - - // t의 문자 개수 카운트 - for (const char of t) { - targetCharCount.set(char, (targetCharCount.get(char) ?? 0) + 1); - } - - const requiredUniqueChars = targetCharCount.size; - let matchedUniqueChars = 0; - const windowCharCount = new Map(); - - let minWindow = ""; - let minWindowLength = Infinity; - - let left = 0, - right = 0; - - while (right < s.length) { - const char = s[right]; - windowCharCount.set(char, (windowCharCount.get(char) ?? 0) + 1); - - // t에 속하는 문자이면서, 문자 개수가 같은 경우 - if ( - targetCharCount.has(char) && - targetCharCount.get(char) === windowCharCount.get(char) - ) - matchedUniqueChars++; - - while (matchedUniqueChars === requiredUniqueChars) { - const windowLength = right - left + 1; - - // 최소 윈도우 업데이트 - if (windowLength < minWindowLength) { - minWindowLength = windowLength; - minWindow = s.substring(left, right + 1); - } - - const leftChar = s[left]; - windowCharCount.set(leftChar, windowCharCount.get(leftChar)! - 1); - - //축소로 윈도우 내의 t문자가 감소했으면 matchedUniqueChars 감소 - if (windowCharCount.get(leftChar)! < targetCharCount.get(leftChar)!) - matchedUniqueChars--; - - // 윈도우 축소 - left++; - } - - // 윈도우 확장 - right++; - } - - return minWindow; -} diff --git a/minimum-window-substring/yolophg.py b/minimum-window-substring/yolophg.py deleted file mode 100644 index 2847c1f50..000000000 --- a/minimum-window-substring/yolophg.py +++ /dev/null @@ -1,40 +0,0 @@ -# Time Complexity: O(N) - go through the string with two pointers, so it's basically O(N). -# Space Complexity: O(1) - only storing character frequencies (max 52 keys for a-z & A-Z), so it's effectively constant space. - -class Solution: - def minWindow(self, s: str, t: str) -> str: - # store character counts for t - target_count = Counter(t) - # window character count - window_count = defaultdict(int) - - # start of the window - left = 0 - # min substring - min_substring = "" - # tracks how many characters match the required count - matched_chars = 0 - # unique characters needed - required_chars = len(target_count) - - for right, char in enumerate(s): - # expand window by adding the rightmost character - if char in target_count: - window_count[char] += 1 - if window_count[char] == target_count[char]: - matched_chars += 1 - - # try shrinking the window if all required characters are present - while matched_chars == required_chars: - # update min substring if this one is shorter - if min_substring == "" or (right - left + 1) < len(min_substring): - min_substring = s[left:right + 1] - - # remove leftmost character and move left pointer - if s[left] in window_count: - window_count[s[left]] -= 1 - if window_count[s[left]] < target_count[s[left]]: - matched_chars -= 1 - left += 1 - - return min_substring diff --git a/pacific-atlantic-water-flow/Chaedie.py b/pacific-atlantic-water-flow/Chaedie.py deleted file mode 100644 index 3a31377f3..000000000 --- a/pacific-atlantic-water-flow/Chaedie.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -Solution: - 1) 가장자리에서 시작해서 어디까지 올라갈수있는지 체크한다. - 2) 교집합을 찾는다. - -Time: O(m * n) -Space: O(m * n) -""" - - -class Solution: - def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: - ROWS, COLS = len(heights), len(heights[0]) - pacific, atlantic = set(), set() - - def dfs(visit, r, c): - if (r, c) in visit: - return - visit.add((r, c)) - - for i, j in [(r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)]: - if 0 <= i and i < ROWS and 0 <= j and j < COLS: - if heights[i][j] >= heights[r][c]: - dfs(visit, i, j) - - for i in range(ROWS): - dfs(pacific, i, 0) - dfs(atlantic, i, COLS - 1) - for i in range(COLS): - dfs(pacific, 0, i) - dfs(atlantic, ROWS - 1, i) - - return list(pacific.intersection(atlantic)) diff --git a/pacific-atlantic-water-flow/Jeehay28.js b/pacific-atlantic-water-flow/Jeehay28.js deleted file mode 100644 index 706626b06..000000000 --- a/pacific-atlantic-water-flow/Jeehay28.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @param {number[][]} heights - * @return {number[][]} - */ - -// ✅ Time Complexity: O(m * n) -// ✅ Space Complexity: O(m * n) - -var pacificAtlantic = function (heights) { - const m = heights.length; - const n = heights[0].length; - - // ❌ Array(m).fill(Array(n).fill(false)) → Incorrect (all rows share the same array) - const pacific = Array.from({ length: m }, () => Array(n).fill(false)); - const atlantic = Array.from({ length: m }, () => Array(n).fill(false)); - - // four possible movement directions: down, up, right, left - const directions = [ - [1, 0], // ⬇️ - [-1, 0], // ⬆️ - [0, 1], // ➡️ - [0, -1], // ⬅️ - ]; - - /** - * Depth-First Search (DFS) to mark reachable cells - * @param {number} row - current row index - * @param {number} col - current column index - * @param {boolean[][]} visited - visited cells - * @param {number} prevHeight - previously visited cell's height - */ - - const dfs = (row, col, visited, prevHeight) => { - // No search needed: - // 1) Out of bounds - // 2) already visited - // 3) current height < previous height - if ( - row < 0 || - row >= m || - col < 0 || - col >= n || - visited[row][col] || - heights[row][col] < prevHeight - ) { - return; - } - - // mark current cell as visited - visited[row][col] = true; - - // visit all four possible directions - for (const [dr, dc] of directions) { - dfs(row + dr, col + dc, visited, heights[row][col]); - } - }; - - // start dfs from each border - for (let i = 0; i < m; i++) { - dfs(i, 0, pacific, heights[i][0]); // left border(Pacific ocean) - dfs(i, n - 1, atlantic, heights[i][n - 1]); // right border(Atlantic ocean) - } - - for (let j = 0; j < n; j++) { - dfs(0, j, pacific, heights[0][j]); // top border(Pacific ocean) - dfs(m - 1, j, atlantic, heights[m - 1][j]); // bottom border(Atlantic ocean) - } - - let result = []; - - for (let r = 0; r < m; r++) { - for (let c = 0; c < n; c++) { - if (pacific[r][c] && atlantic[r][c]) { - result.push([r, c]); - } - } - } - return result; -}; - -// Example test -const heights = [ - [1, 2, 2, 3, 5], - [3, 2, 3, 4, 4], - [2, 4, 5, 3, 1], - [6, 7, 1, 4, 5], - [5, 1, 1, 2, 4], -]; - -const expected = [ - [0, 4], - [1, 3], - [1, 4], - [2, 2], - [3, 0], - [3, 1], - [4, 0], -]; - -const output = pacificAtlantic(heights); - -if (JSON.stringify(output.sort()) === JSON.stringify(expected.sort())) { - console.log("✅ Accepted\n"); -} else { - console.log("❌ Not Accepted\n"); -} - -console.log("Input:", heights, "\n"); -console.log("Output:", output, "\n"); -console.log("Expected:", expected); - diff --git a/pacific-atlantic-water-flow/dusunax.py b/pacific-atlantic-water-flow/dusunax.py deleted file mode 100644 index 7588a41cd..000000000 --- a/pacific-atlantic-water-flow/dusunax.py +++ /dev/null @@ -1,42 +0,0 @@ -''' -# 417. Pacific Atlantic Water Flow - -## Time Complexity: O(n * m) -- dfs is called for each cell in the grid, and each cell is visited once. - -## Space Complexity: O(n * m) -- pacific and atlantic sets store the cells that can flow to the pacific and atlantic oceans respectively. -''' -class Solution: - def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: - if len(heights) == 1 and len(heights[0]) == 1: - return [[0, 0]] - - max_row, max_col = len(heights), len(heights[0]) - pacific, atlantic = set(), set() - directions = [(1, 0), (0, 1), (-1, 0), (0, -1)] - - def dfs(r, c, visited, prev_height): - out_of_bound = r < 0 or c < 0 or r >= max_row or c >= max_col - if out_of_bound: - return - - current = heights[r][c] - is_visited = (r, c) in visited - is_uphill = current < prev_height - if is_visited or is_uphill: - return - - visited.add((r, c)) - - for dr, dc in directions: - dfs(r + dr, c + dc, visited, current) - - for r in range(max_row): - dfs(r, 0, pacific, heights[r][0]) # left - dfs(r, max_col - 1, atlantic, heights[r][max_col - 1]) # right - for c in range(max_col): - dfs(0, c, pacific, heights[0][c]) # top - dfs(max_row - 1, c, atlantic, heights[max_row - 1][c]) # bottom - - return list(pacific & atlantic) diff --git a/pacific-atlantic-water-flow/ekgns33.java b/pacific-atlantic-water-flow/ekgns33.java deleted file mode 100644 index 2f3975576..000000000 --- a/pacific-atlantic-water-flow/ekgns33.java +++ /dev/null @@ -1,62 +0,0 @@ -/* -* input : grid represents the heights of island -* output : coordinates where water flows to both pacific and atlantic -* -* example -* -* 2 2 2 1,1 >> 1,2 >> atlantic / 1,1 >> 0,1 >> pacific -* 3 3 1 -* 4 3 1 -* -* do dfs/bfs from the edge of grids. -* if cell is checked from pacific and atlantic add to result -* solution dfs from edges -* tc : O(m*n) -* sc : O(mn) -* -* */ -class Solution { - public List> pacificAtlantic(int[][] heights) { - int m = heights.length; - int n = heights[0].length; - int[][] pacific = new int[m][n]; - int[][] atlantic = new int[m][n]; - - for(int i = 0; i < m; i++) { - dfsHelper(heights, pacific, i, 0); - } - for(int j = 1; j < n; j++) { - dfsHelper(heights,pacific, 0, j); - } - for(int i =0; i < m; i++) { - dfsHelper(heights,atlantic, i, n-1); - } - for(int j = 0; j < n-1; j++) { - dfsHelper(heights, atlantic, m-1, j); - } - List> ans = new ArrayList<>(); - for(int i = 0; i < m; i++) { - for(int j = 0; j < n; j++) { - if(pacific[i][j] == 1 && atlantic[i][j] == 1) { - ans.add(List.of(i, j)); - } - } - } - return ans; - } - - static int[][] directions = { - {1, 0}, {-1, 0}, {0, 1}, {0, -1} - }; - - void dfsHelper(int[][] board, int[][] visited, int x, int y) { - if(visited[x][y] > 0) return; - visited[x][y] += 1; - for(int[] direction : directions) { - int nx = x + direction[0]; - int ny = y + direction[1]; - if(nx < 0 || nx >=visited.length || ny < 0 || ny >= visited[0].length || visited[nx][ny] > 0 || board[nx][ny] < board[x][y]) continue; - dfsHelper(board, visited, nx, ny); - } - } -} diff --git a/pacific-atlantic-water-flow/eunhwa99.java b/pacific-atlantic-water-flow/eunhwa99.java deleted file mode 100644 index b4d819c30..000000000 --- a/pacific-atlantic-water-flow/eunhwa99.java +++ /dev/null @@ -1,63 +0,0 @@ -import java.util.ArrayList; -import java.util.List; - -class Solution { - - // TP: O(N*N) - // SP: O(N*N) - // pacific에 접하는 지점으로부터 dfs를 시작해 pacific에 도달할 수 있는 지점을 체크하고, - // atlantic에 접하는 지점으로부터 dfs를 시작해 atlantic에 도달할 수 있는 지점을 체크한다. - // 마지막으로 두 지점 모두에 도달할 수 있는 지점을 찾아 반환한다. - int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - - public List> pacificAtlantic(int[][] heights) { - int rowSize = heights.length; - int colSize = heights[0].length; - - boolean[][] pacific = new boolean[rowSize][colSize]; - boolean[][] atlantic = new boolean[rowSize][colSize]; - - for (int i = 0; i < rowSize; i++) { - dfs(i, 0, pacific, heights); - dfs(i, colSize - 1, atlantic, heights); - } - - for (int i = 0; i < colSize; i++) { - dfs(0, i, pacific, heights); - dfs(rowSize - 1, i, atlantic, heights); - } - - List> result = new ArrayList<>(); - for (int i = 0; i < rowSize; i++) { - for (int j = 0; j < colSize; j++) { - if (pacific[i][j] && atlantic[i][j]) { - result.add(List.of(i, j)); - } - } - } - return result; - } - - private void dfs(int row, int col, boolean[][] visited, int[][] heights) { - visited[row][col] = true; - - for (int[] direction : directions) { - int newRow = row + direction[0]; - int newCol = col + direction[1]; - - if (newRow < 0 || newRow >= heights.length || newCol < 0 || newCol >= heights[0].length) { - continue; - } - - if (visited[newRow][newCol]) { - continue; - } - - if (heights[newRow][newCol] < heights[row][col]) { - continue; - } - - dfs(newRow, newCol, visited, heights); - } - } -} diff --git a/pacific-atlantic-water-flow/mike2ox.ts b/pacific-atlantic-water-flow/mike2ox.ts deleted file mode 100644 index 1a3374b43..000000000 --- a/pacific-atlantic-water-flow/mike2ox.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Source: https://leetcode.com/problems/pacific-atlantic-water-flow/ - * 풀이방법: DFS를 이용하여 pacific과 atlantic에서 물이 흐르는 지점을 찾음 - * - * 시간복잡도: O(n * m) (n: 행의 개수, m: 열의 개수) - * 공간복잡도: O(n * m) - */ - -function pacificAtlantic(heights: number[][]): number[][] { - if (!heights || !heights[0]) return []; - - const rows = heights.length; - const cols = heights[0].length; - - // checklist - const pacific = new Set(); - const atlantic = new Set(); - - // DFS - function dfs( - row: number, - col: number, - prevHeight: number, - visited: Set - ) { - // row, col이 경계 밖이거나 이미 방문했거나 이전 높이보다 낮은 경우 - if ( - row < 0 || - row >= rows || - col < 0 || - col >= cols || - heights[row][col] < prevHeight || - visited.has(`${row},${col}`) - ) { - return; - } - - // 현재 위치 체크 - visited.add(`${row},${col}`); - - // 4방향 탐색 - dfs(row + 1, col, heights[row][col], visited); - dfs(row - 1, col, heights[row][col], visited); - dfs(row, col + 1, heights[row][col], visited); - dfs(row, col - 1, heights[row][col], visited); - } - - // 0,0에서부터 탐색 시작 - for (let col = 0; col < cols; col++) { - dfs(0, col, heights[0][col], pacific); - } - for (let row = 0; row < rows; row++) { - dfs(row, 0, heights[row][0], pacific); - } - - // rows-1, cols-1(pacific하고는 정반대 위치에서 시작) - for (let col = 0; col < cols; col++) { - dfs(rows - 1, col, heights[rows - 1][col], atlantic); - } - for (let row = 0; row < rows; row++) { - dfs(row, cols - 1, heights[row][cols - 1], atlantic); - } - - const result: number[][] = []; - for (let row = 0; row < rows; row++) { - for (let col = 0; col < cols; col++) { - const pos = `${row},${col}`; - if (pacific.has(pos) && atlantic.has(pos)) { - result.push([row, col]); - } - } - } - - return result; -} diff --git a/pacific-atlantic-water-flow/mmyeon.ts b/pacific-atlantic-water-flow/mmyeon.ts deleted file mode 100644 index dd4cac5e7..000000000 --- a/pacific-atlantic-water-flow/mmyeon.ts +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @link https://leetcode.com/problems/pacific-atlantic-water-flow/description/ - * - * 접근 방법 : - * - pacific, atlantic를 동시에 도달하는 지점 찾기 위해서, 도달 여부 트래킹하는 2개의 visited 배열 사용한다. - * - 바다 경계에서만 DFS를 호출해서 방문 여부 체크한다. - * - 바다 경계에서 시작했기 때문에 DFS는 인접 셀의 높이가 같거나 높을 때만 호출되어야 한다. - * - * 시간복잡도 : O(m * n) - * - 각 셀마다 최대 4번 DFS가 호출될 수 있다. O(m * n) - * - 결과 순회할 때 m * n 만큼 순회한다. - * - * 공간복잡도 : O(m * n) - * - 2개의 visited 배열 사용한다. - * - 최악의 경우, m * n 모든 칸에서 DFS 호출된다. - */ - -const directions = [ - [-1, 0], - [1, 0], - [0, -1], - [0, 1], -]; - -function pacificAtlantic(heights: number[][]): number[][] { - const result: number[][] = []; - - const rows = heights.length; - const cols = heights[0].length; - - // 두 바다 도달하는 지점 트래킹 하기 위한 배열 - const pacificVisited = Array.from({ length: rows }, () => - Array(cols).fill(false) - ); - const atlanticVisited = Array.from({ length: rows }, () => - Array(cols).fill(false) - ); - - const dfs = (row: number, col: number, visited: boolean[][]) => { - if (visited[row][col]) return; - // 방문 지점 기록 - visited[row][col] = true; - - for (const [x, y] of directions) { - const newRow = row + x; - const newCol = col + y; - - // 새로운 위치가 경계안에 있고, 현재 높이보다 같거나 높을 때만 DFS 호출 - if ( - 0 <= newRow && - newRow < rows && - 0 <= newCol && - newCol < cols && - heights[newRow][newCol] >= heights[row][col] - ) - dfs(newRow, newCol, visited); - } - }; - - // pacific 경계에서 DFS 호출 (첫 번쨰 열, 첫 번째 행) - for (let row = 0; row < rows; row++) dfs(row, 0, pacificVisited); - for (let col = 0; col < cols; col++) dfs(0, col, pacificVisited); - - // atlantic 경계에서 DFS 호출 (마지막 열, 마지막 행) - for (let row = 0; row < rows; row++) dfs(row, cols - 1, atlanticVisited); - for (let col = 0; col < cols; col++) dfs(rows - 1, col, atlanticVisited); - - for (let row = 0; row < rows; row++) { - for (let col = 0; col < cols; col++) { - if (pacificVisited[row][col] && atlanticVisited[row][col]) - result.push([row, col]); - } - } - - return result; -} diff --git a/pacific-atlantic-water-flow/pmjuu.py b/pacific-atlantic-water-flow/pmjuu.py deleted file mode 100644 index 422b6dd95..000000000 --- a/pacific-atlantic-water-flow/pmjuu.py +++ /dev/null @@ -1,71 +0,0 @@ -''' -시간 복잡도: O(m * n) -- 각 바다에서 BFS를 한 번씩 수행하며, 각 셀을 최대 한 번씩 방문하므로 O(m * n)입니다. - -공간 복잡도: O(m * n) -- BFS 탐색을 위한 큐와 방문한 셀을 저장하는 집합(set)이 필요하므로 O(m * n)입니다. -''' - -from collections import deque -from typing import List - -class Solution: - def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: - m, n = len(heights), len(heights[0]) - directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] - - def bfs(starts): - queue = deque(starts) - reachable = set(starts) - - while queue: - r, c = queue.popleft() - for dr, dc in directions: - nr, nc = r + dr, c + dc - if (0 <= nr < m and 0 <= nc < n and - (nr, nc) not in reachable and - heights[nr][nc] >= heights[r][c]): # 물이 흐를 수 있는지 확인 - queue.append((nr, nc)) - reachable.add((nr, nc)) - - return reachable - - # 태평양(왼쪽과 위쪽 가장자리)에서 시작하는 셀들 - pacific_starts = [(0, c) for c in range(n)] + [(r, 0) for r in range(m)] - # 대서양(오른쪽과 아래쪽 가장자리)에서 시작하는 셀들 - atlantic_starts = [(m-1, c) for c in range(n)] + [(r, n-1) for r in range(m)] - - pacific_reach = bfs(pacific_starts) - atlantic_reach = bfs(atlantic_starts) - - return list(pacific_reach & atlantic_reach) - - -class Solution: - def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: - if not heights or not heights[0]: - return [] - - m, n = len(heights), len(heights[0]) - directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] - - def dfs(r, c, reachable): - reachable.add((r, c)) - for dr, dc in directions: - nr, nc = r + dr, c + dc - if (0 <= nr < m and 0 <= nc < n and - (nr, nc) not in reachable and - heights[nr][nc] >= heights[r][c]): - dfs(nr, nc, reachable) - - pacific_reach, atlantic_reach = set(), set() - - for c in range(n): - dfs(0, c, pacific_reach) - dfs(m-1, c, atlantic_reach) - - for r in range(m): - dfs(r, 0, pacific_reach) - dfs(r, n-1, atlantic_reach) - - return list(pacific_reach & atlantic_reach) diff --git a/pacific-atlantic-water-flow/yolophg.py b/pacific-atlantic-water-flow/yolophg.py deleted file mode 100644 index 4c92a1071..000000000 --- a/pacific-atlantic-water-flow/yolophg.py +++ /dev/null @@ -1,44 +0,0 @@ -# Time Complexity: O(m * n) - running DFS from each border, so worst case, we visit each cell twice. -# Space Complexity: O(m * n) - using two sets to track which cells can reach each ocean and the recursion stack. - -class Solution: - def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: - - rows = len(heights) - cols = len(heights[0]) - result = [] - - # tracking which cells can reach each ocean - pac, atl = set(), set() - - def dfs(r, c, visited, preHeight): - # if out of bounds, already visited, or can't flow from prev height → just dip - if (r < 0 or c < 0 or r == rows or c == cols or - (r, c) in visited or heights[r][c] < preHeight): - return - - # mark as visited - visited.add((r, c)) - - # go in all 4 directions - dfs(r + 1, c, visited, heights[r][c]) # down - dfs(r - 1, c, visited, heights[r][c]) # up - dfs(r, c + 1, visited, heights[r][c]) # right - dfs(r, c - 1, visited, heights[r][c]) # left - - # hit up all border cells for both oceans - for c in range(cols): - dfs(0, c, pac, heights[0][c]) # top row (pacific) - dfs(rows - 1, c, atl, heights[rows - 1][c]) # bottom row (atlantic) - - for r in range(rows): - dfs(r, 0, pac, heights[r][0]) # leftmost col (pacific) - dfs(r, cols - 1, atl, heights[r][cols - 1]) # rightmost col (atlantic) - - # now just check which cells are in both sets - for r in range(rows): - for c in range(cols): - if (r, c) in pac and (r, c) in atl: - result.append([r, c]) - - return result From 3b90026f35465189b7f099cbec358eca756a0ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=81=EC=9E=AC?= Date: Mon, 10 Feb 2025 20:59:15 +0900 Subject: [PATCH 11/11] =?UTF-8?q?del:=209=EC=A3=BC=EC=B0=A8=20pr=EC=9D=84?= =?UTF-8?q?=20=EC=9C=84=ED=95=9C=2010=EC=A3=BC=EC=B0=A8=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- invert-binary-tree/Yjason-K.ts | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 invert-binary-tree/Yjason-K.ts diff --git a/invert-binary-tree/Yjason-K.ts b/invert-binary-tree/Yjason-K.ts deleted file mode 100644 index 26fc1cf89..000000000 --- a/invert-binary-tree/Yjason-K.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * 이진 트리를 반전시키는 함수 - * @param {TreeNode | null} root - 반전할 이진 트리의 루트 노드 - * @returns {TreeNode | null} - 반전된 이진 트리의 루트 노드 - * - * 시간 복잡도: O(n) - * - 트리의 모든 노드를 한 번씩 방문해야 하므로 선형 시간 복잡도를 가짐 - * 공간 복잡도: O(h) - * - 재귀 호출에 의해 최대 트리의 높이(h)만큼의 호출 스택이 필요 - */ -function invertTree(root: TreeNode | null): TreeNode | null { - // 루트가 null이면 null 반환 - if (!root) return null; - - // 왼쪽과 오른쪽 서브트리를 재귀적으로 반전 - const left = invertTree(root.left); - const right = invertTree(root.right); - - // 현재 노드의 왼쪽과 오른쪽 서브트리를 교환 - root.left = right; - root.right = left; - - // 반전된 루트 노드를 반환 - return root; - } - - \ No newline at end of file