Skip to content

[hi-rachel] Week 04 Solutions #1340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions coin-change/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +29 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hi-rachel 님 안녕하세요. 이번 주도 고생하셨습니다. 저는 문제를 풀 때 dp로 접근하는 것을 어려워하는 편이라서, 특히 dp 풀이법을 인상깊게 봤습니다. 다음 주도 파이팅하세요 💪

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 전체적으로 풀이가 깔끔해서 나중에 공부할 때도 참고가 될 것 같습니다. 감사합니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hi-rachel 님 안녕하세요. 이번 주도 고생하셨습니다. 저는 문제를 풀 때 dp로 접근하는 것을 어려워하는 편이라서, 특히 dp 풀이법을 인상깊게 봤습니다. 다음 주도 파이팅하세요 💪

@KwonNayeon 님 안녕하세요 :) 저만 dp가 어려운게 아니였군여ㅜㅜ 저도 dp 문제는 이해 안가는 문제들이 많아서 힘들었는데 다행히 이 문제는 알고달레의 설명을 보고 이해했습니다. 저도 못풀어서 알고달레 풀이를 참고했는데 자세한 풀이를 원하실 때 추천드립니다. 감사합니다~

https://www.algodale.com/problems/coin-change/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 dp는 간단한 문제 아니면 응용하기 너무 어렵더라구요...😂 역시 알고달레 👍 정말 감사합니다!

Copy link
Contributor Author

@hi-rachel hi-rachel Apr 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 dp는 간단한 문제 아니면 응용하기 너무 어렵더라구요...😂 역시 알고달레 👍 정말 감사합니다!

@KwonNayeon dp + 재귀 + 백트래킹 넘나 어려워요.. 이번 스터디 끝날 때쯤에는 사고가 넓어져있길! 같이 파이팅합시다! 감사합니다.

11 changes: 11 additions & 0 deletions coin-change/hi-rachel.ts
Original file line number Diff line number Diff line change
@@ -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;
}
28 changes: 28 additions & 0 deletions find-minimum-in-rotated-sorted-array/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -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]
17 changes: 17 additions & 0 deletions find-minimum-in-rotated-sorted-array/hi-rachel.ts
Original file line number Diff line number Diff line change
@@ -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];
}
44 changes: 44 additions & 0 deletions maximum-depth-of-binary-tree/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -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))
57 changes: 57 additions & 0 deletions maximum-depth-of-binary-tree/hi-rachel.ts
Original file line number Diff line number Diff line change
@@ -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;
// }
33 changes: 33 additions & 0 deletions merge-two-sorted-lists/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -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
45 changes: 45 additions & 0 deletions merge-two-sorted-lists/hi-rachel.ts
Original file line number Diff line number Diff line change
@@ -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;
}
33 changes: 33 additions & 0 deletions word-search/hi-rachel.py
Original file line number Diff line number Diff line change
@@ -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