Skip to content
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
38 changes: 38 additions & 0 deletions coin-change/radiantchoi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from collections import deque

class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
# BFS를 이용한 최소 동전 개수 찾기
# 동전을 하나씩 추가하면서 만들 수 있는 금액을 탐색 (레벨별 탐색)
# BFS 특성상 먼저 도달하는 경로가 최소 동전 개수 보장
# dp[i]: amount가 i일 때 최소 동전 사용 횟수
# 모든 경우 방법이 없다고 가정하고 -1로 초기화
dp = [-1 for _ in range(amount + 1)]

# bfs 셋업 - 합이 0인 노드를 방문하고, 방문 처리
dp[0] = 0
# 큐의 각 요소: [사용한 동전 개수, 현재까지의 합]
# 시작 상태: 동전 0개, 합 0
q = deque([[0, 0]])

while q:
# current[0]: 사용한 동전 개수, current[1]: 현재까지의 합
current = q.popleft()

# 각각의 동전은 무한히 사용할 수 있으므로, 가능한 경우 모두 탐색
for coin in coins:
estimated = current[1] + coin

# estimated <= amount: 목표 금액을 초과하지 않는 경우만 탐색
# dp[estimated] == -1: 아직 방문하지 않은 금액 (BFS 특성상 최초 도달이 최적)
# 두 조건 모두 통과하면 큐에 추가하여 계속 탐색
if estimated <= amount and dp[estimated] == -1:
used = current[0] + 1
dp[estimated] = used

new = [used, estimated]
q.append(new)

# dp[amount]가 -1이면 모든 경우 방법이 없다는 의미이므로 -1 반환
# 그렇지 않다면 dp[amount] 반환
return dp[amount]
36 changes: 36 additions & 0 deletions maximum-depth-of-binary-tree/radiantchoi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Definition for a binary tree node.
* public class TreeNode {
* public var val: Int
* public var left: TreeNode?
* public var right: TreeNode?
* public init() { self.val = 0; self.left = nil; self.right = nil; }
* public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; }
* public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) {
* self.val = val
* self.left = left
* self.right = right
* }
* }
*/
class Solution {
func maxDepth(_ root: TreeNode?) -> Int {
var result = 0

traverse(root, 0, &result)

return result
}

func traverse(_ node: TreeNode?, _ current: Int, _ result: inout Int) {
guard let node else {
result = max(current, result)
return
}

let newCurrent = current + 1

traverse(node.left, newCurrent, &result)
traverse(node.right, newCurrent, &result)
}
}
31 changes: 31 additions & 0 deletions merge-two-sorted-lists/radiantchoi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Definition for singly-linked list.
# 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]:
head = ListNode()
result = head

while list1 and list2:
if list1.val <= list2.val:
head.next = ListNode(list1.val)
head = head.next
list1 = list1.next
else:
head.next = ListNode(list2.val)
head = head.next
list2 = list2.next

while list1:
Copy link
Contributor

Choose a reason for hiding this comment

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

while list1:
....
while list2:
..

이쪽 부분에서 다시 반복문을 도는 이유가 list1 이나 list2 둘중에
하나가 비어있을때를 고려하신걸까요?

만약 맞다면 list1 과 list2 둘중 하나만 리스트가 존재할때
이미 정렬되어있는 상태이기 떄문에 그대로 반환해도 될것같아 보여요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네 정확히 그런 케이스입니다! 저도 리뷰를 하면서 알게 된 것인데, 반복문을 다시 돌 것이 아니라, 리스트1과 리스트2중 하나 이하만 남아 있을 것이 분명하므로 그대로 현재 답안 리스트의 next로 붙여도 되겠더라구요.

head.next = ListNode(list1.val)
head = head.next
list1 = list1.next

while list2:
head.next = ListNode(list2.val)
head = head.next
list2 = list2.next

return result.next
54 changes: 54 additions & 0 deletions word-search/radiantchoi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class Solution {
func exist(_ board: [[Character]], _ word: String) -> Bool {
let target = Array(word) // Swift String은 인덱스를 통한 접근에 어려움이 있어, Array로 변환
let threshold = target.count
var board = board // inout 파라미터로 사용하기 위해 변수로 변환

for i in 0..<board.count {
for j in 0..<board[i].count {
// 백트래킹 순회 함수
// 조건에 맞는 결과가 있으면 바로 true 반환 - early return
if traverse(&board, 0, i, j, threshold, target) {
return true
}
}
}

// 모든 좌표를 순회한 후에도 매칭되는 결과가 없으면 false 반환
return false
}

// threshold를 target.count로 사용할 수 있으나, 매번 계산하지 않기 위해 부모 함수에서 한 번만 계산하고 파라미터에 포함
func traverse(_ board: inout [[Character]], _ checked: Int, _ row: Int, _ col: Int, _ threshold: Int, _ target: [Character]) -> Bool {
// 지금까지 체크한 글자 수가 단어의 총 글자 수와 같다면, true 반환
// 아래의 조건에 따라 매칭되지 않는다면 그 이전에 false가 반환되었을 것이기 때문
if checked == threshold {
return true
}

// 현재 좌표가 보드의 범위를 벗어난다면 false 반환
guard (0..<board.count) ~= row && (0..<board[0].count) ~= col else {
return false
}

// 현재 좌표의 글자가 단어의 현재 체크해야 할 글자와 일치하지 않는다면 바로 false 반환
guard board[row][col] == target[checked] else {
return false
}

// 백트래킹 스텝 1: 현재 좌표의 글자를 임시 변수에 저장하고, 현재 좌표의 글자를 "#"로 변경
let temp = board[row][col]
board[row][col] = "#"

// 백트래킹 스텝 2: 현재 좌표의 상하좌우를 순회하며, 매칭되는 결과가 있으면 true 반환
let result = traverse(&board, checked + 1, row + 1, col, threshold, target)
|| traverse(&board, checked + 1, row - 1, col, threshold, target)
|| traverse(&board, checked + 1, row, col + 1, threshold, target)
|| traverse(&board, checked + 1, row, col - 1, threshold, target)

// 백트래킹 스텝 3: 현재 좌표의 글자를 원래 값으로 복구
board[row][col] = temp

return result
}
}