diff --git a/coin-change/hi-rachel.py b/coin-change/hi-rachel.py new file mode 100644 index 000000000..5a927ef26 --- /dev/null +++ b/coin-change/hi-rachel.py @@ -0,0 +1,37 @@ + +# BFS -> 먼저 찾는 해답이 가장 적은 연산/가장 짧은 거리 -> 가장 적은 count부터 계산해 최소한의 동전 수 보장 +# O(amount * n) time, O(amount) space + +from collections import deque + +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + queue = deque([(0, 0)]) # (동전 개수, 현재 금액) + visited = set() + while queue: + count, total = queue.popleft() + if total == amount: + return count + if total in visited: + continue + visited.add(total) + for coin in coins: + if total + coin <= amount: + queue.append((count + 1, total + coin)) + return - 1 + + +# DP 풀이 +# 어떤 금액을 만드는데 필요한 동전 개수를 알면, 그 금액보다 큰 금액을 만드는데 필요한 동전 개수도 알 수 있다. +# dp[i] = min(dp[i], dp[i - coin] + 1) +# O(amount * n) time, O(amount) space + +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + dp = [0] + [amount + 1] * amount + + for coin in coins: + for i in range(coin, amount + 1): + dp[i] = min(dp[i], dp[i - coin] + 1) + + return dp[amount] if dp[amount] < amount + 1 else -1 diff --git a/coin-change/hi-rachel.ts b/coin-change/hi-rachel.ts new file mode 100644 index 000000000..11dfea8c8 --- /dev/null +++ b/coin-change/hi-rachel.ts @@ -0,0 +1,11 @@ +function coinChange(coins: number[], amount: number): number { + const dp = [0, ...new Array(amount).fill(amount + 1)]; + for (let i = 0; i <= amount; i++) { + for (const coin of coins) { + if (coin <= i) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + return dp[amount] < amount + 1 ? dp[amount] : -1; +} diff --git a/find-minimum-in-rotated-sorted-array/hi-rachel.py b/find-minimum-in-rotated-sorted-array/hi-rachel.py new file mode 100644 index 000000000..d55213bc5 --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/hi-rachel.py @@ -0,0 +1,28 @@ +# 회전된 오름차순 배열에서 최소값을 이진 탐색으로 찾아라 + +# O(N) time, O(1) space -> 시간 복잡도 충족 x +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] + + +class Solution: + + +# 이진 탐색 풀이 +# O(log n) time, O(1) space +class Solution: + def findMin(self, nums: List[int]) -> int: + low, high = 1, len(nums) - 1 + while low <= high: + mid = (low + high) // 2 + if nums[mid - 1] > nums[mid]: + return nums[mid] + if nums[0] < nums[mid]: + low = mid + 1 + else: + high = mid - 1 + return nums[0] diff --git a/find-minimum-in-rotated-sorted-array/hi-rachel.ts b/find-minimum-in-rotated-sorted-array/hi-rachel.ts new file mode 100644 index 000000000..08f376f12 --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/hi-rachel.ts @@ -0,0 +1,17 @@ +function findMin(nums: number[]): number { + let low = 0, + high = nums.length - 1; + + while (low <= high) { + let mid = Math.floor((low + high) / 2); + if (nums[mid - 1] > nums[mid]) { + return nums[mid]; // 회전이 일어난 곳 + } + if (nums[0] < nums[mid]) { + low = mid + 1; // 왼쪽은 이미 정렬되어 있어, 오른쪽으로 이동 + } else { + high = mid - 1; // 왼쪽으로 이동 + } + } + return nums[0]; +} diff --git a/maximum-depth-of-binary-tree/hi-rachel.py b/maximum-depth-of-binary-tree/hi-rachel.py new file mode 100644 index 000000000..0dc2e2d8d --- /dev/null +++ b/maximum-depth-of-binary-tree/hi-rachel.py @@ -0,0 +1,44 @@ +# O(n) time, 모든 노드를 한 번씩 방문 +# O(h) for DFS / O(w) for BFS space, DFS는 재귀 호출 깊이 (h = 트리 높이), BFS는 큐에 들어가는 최대 노드 수 (w = 최대 너비) + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right + + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +# BFS 풀이 +from collections import deque + +class Solution: + def maxDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + + queue = deque([root]) + depth = 0 + + while queue: + for _ in range(len(queue)): + node = queue.popleft() + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + depth += 1 + return depth + +# DFS 풀이 +class Solution: + def maxDepth(self, root: Optional[TreeNode]) -> int: + if not root: + return 0 + return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) diff --git a/maximum-depth-of-binary-tree/hi-rachel.ts b/maximum-depth-of-binary-tree/hi-rachel.ts new file mode 100644 index 000000000..85e8940ae --- /dev/null +++ b/maximum-depth-of-binary-tree/hi-rachel.ts @@ -0,0 +1,57 @@ +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ + +// O(n) time, 모든 노드를 한 번씩 방문 +// O(h) for DFS / O(w) for BFS space, DFS는 재귀 호출 깊이 (h = 트리 높이), BFS는 큐에 들어가는 최대 노드 수 (w = 최대 너비) + +class TreeNode { + val: number; + left: TreeNode | null; + right: TreeNode | null; + constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + this.val = val === undefined ? 0 : val; + this.left = left === undefined ? null : left; + this.right = right === undefined ? null : right; + } +} + +// BFS 풀이 +function maxDepth(root: TreeNode | null): number { + if (root === null) return 0; + + const queue: TreeNode[] = [root]; + let depth = 0; + + while (queue.length > 0) { + const levelSize = queue.length; + + for (let i = 0; i < levelSize; i++) { + const node = queue.shift(); + if (node) { + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + } + depth++; + } + return depth; +} + +// DFS 풀이 +// function maxDepth(root: TreeNode | null): number { +// if (root === null) return 0; +// const left = maxDepth(root.left); +// const right = maxDepth(root.right); +// return Math.max(left, right) + 1; +// } diff --git a/merge-two-sorted-lists/hi-rachel.py b/merge-two-sorted-lists/hi-rachel.py new file mode 100644 index 000000000..feac43c7a --- /dev/null +++ b/merge-two-sorted-lists/hi-rachel.py @@ -0,0 +1,33 @@ +# O(n + m) time, n = list1의 노드 수 / m = list2의 노드 수 +# O(1) space, 연결된 새 리스트는 기존 노드들을 재사용해서 만듬 + +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next + +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + +class Solution: + def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + dummy = ListNode() + tail = dummy + + while list1 and list2: + if list1.val < list2.val: + tail.next = list1 + list1 = list1.next + else: + tail.next = list2 + list2 = list2.next + tail = tail.next + + if list1: + tail.next = list1 + if list2: + tail.next = list2 + return dummy.next diff --git a/merge-two-sorted-lists/hi-rachel.ts b/merge-two-sorted-lists/hi-rachel.ts new file mode 100644 index 000000000..91fab1bc6 --- /dev/null +++ b/merge-two-sorted-lists/hi-rachel.ts @@ -0,0 +1,45 @@ +/** + * 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) + * } + * } + */ + +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 mergeTwoLists( + list1: ListNode | null, + list2: ListNode | null +): ListNode | null { + const dummy = new ListNode(); + let tail = dummy; + while (list1 !== null && list2 !== null) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + if (list1 !== null) { + tail.next = list1; + } + if (list2 !== null) { + tail.next = list2; + } + return dummy.next; +} diff --git a/word-search/hi-rachel.py b/word-search/hi-rachel.py new file mode 100644 index 000000000..446cd033f --- /dev/null +++ b/word-search/hi-rachel.py @@ -0,0 +1,33 @@ +# DFS 풀이 +# board 높이: m, 넓이: n, w: 단어의 길이 +# TC: (m * n * 4^w) -> 4^w 상하좌우 탐색 * 글자판 내의 모든 좌표를 상대로 수행함 +# SC: O(m * n + w) -> traversing 집합 메모리는 글자판의 크기의 비례 + dfs 호출 스택의 깊이가 단어의 길이에 비례해 증가 + +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + n_rows, n_cols = len(board), len(board[0]) + traversing = set() + + def dfs(row, col, idx): + if idx == len(word): + return True + if not (0 <= row < n_rows and 0 <= col < n_cols): + return False + if (row, col) in traversing: + return False + if board[row][col] != word[idx]: + return False + + traversing.add((row, col)) + # 상하좌우 탐색 + for (r, c) in [(-1, 0), (1, 0), (0, -1), (0, 1)]: + if dfs(row + r, col + c, idx + 1): + return True + traversing.remove((row, col)) + return False + + for i in range(n_rows): + for j in range(n_cols): + if dfs(i, j, 0): + return True + return False