From 88214b4a4a44f92b5e69b80ea1db151a7692b7a0 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 21:30:03 +0900 Subject: [PATCH] add: #245 #225 #270 #260 9th week --- .../Yjason-K.ts | 31 ++++++++ linked-list-cycle/Yjason-K.ts | 37 +++++++++ maximum-product-subarray/Yjason-K.ts | 32 ++++++++ pacific-atlantic-water-flow/Yjason-K.ts | 76 +++++++++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 find-minimum-in-rotated-sorted-array/Yjason-K.ts create mode 100644 linked-list-cycle/Yjason-K.ts create mode 100644 maximum-product-subarray/Yjason-K.ts create mode 100644 pacific-atlantic-water-flow/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]; + +} + diff --git a/linked-list-cycle/Yjason-K.ts b/linked-list-cycle/Yjason-K.ts new file mode 100644 index 000000000..31eb00430 --- /dev/null +++ b/linked-list-cycle/Yjason-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; +} + diff --git a/maximum-product-subarray/Yjason-K.ts b/maximum-product-subarray/Yjason-K.ts new file mode 100644 index 000000000..9eed79489 --- /dev/null +++ b/maximum-product-subarray/Yjason-K.ts @@ -0,0 +1,32 @@ +/** + * 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; +} + 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; +}; +