From 276ce109c79db4ac47b0cac22f58c8b22abbf44a Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Tue, 14 Jul 2026 00:46:51 +0900 Subject: [PATCH 1/9] 21. Merge Two Sorted Lists --- merge-two-sorted-lists/okyungjin.py | 110 ++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 merge-two-sorted-lists/okyungjin.py diff --git a/merge-two-sorted-lists/okyungjin.py b/merge-two-sorted-lists/okyungjin.py new file mode 100644 index 0000000000..3460b990ff --- /dev/null +++ b/merge-two-sorted-lists/okyungjin.py @@ -0,0 +1,110 @@ +# from typing import Optional, List + +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next + +# # 파이썬의 toString 역할을 하는 __repr__을 [1,3,4] 형태로 출력되게 수정 +# def __repr__(self): +# nodes = [] +# curr = self +# while curr: +# nodes.append(str(curr.val)) +# curr = curr.next +# return "[" + ",".join(nodes) + "]" + +# # 파이썬 list를 ListNode 리스트로 변환해주는 헬퍼 함수 +# def make_linked_list(arr: List[int]) -> Optional[ListNode]: +# if not arr: +# return None +# dummy = ListNode(0) +# curr = dummy +# for val in arr: +# curr.next = ListNode(val) +# curr = curr.next +# return dummy.next + + +# list1의 노드 개수를 n, list2의 노드 개수를 m이라 할 때 +# 시간 복잡도: O(n + m) +# 공간 복잡도: O(n + m) -> +class Solution_01: + def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + # 맨 앞에 더미 노드를 하나 추가한다 + # 없는 상태로 짰는데 if node: else: 구문 늘어나서 맨 앞에 가상의 노드를 하나 추가해줬다 + dummy = ListNode(None) + node = dummy + + while True: + # list1이 비어있으면 현재 노드 뒤로 list2를 이어준다. + if not list1: + node.next = list2 + break + + # list2가 비어있으면 현재 노드 뒤로 list1을 이어준다. + if not list2: + node.next = list1 + break + + # 값을 비교해서 작은 값을 next 노드에 추가한다. + if list1.val <= list2.val: + node.next = ListNode(list1.val) + # list1 하나 소비 + list1 = list1.next + else: + node.next = ListNode(list2.val) + # list2 하나 소비 + list2 = list2.next + + # 다음 노드를 현재 노드로 할당해준다 + node = node.next + + return dummy.next + + +# [접근법] Solution_01 의 공간 복잡도를 개선했습니다. +# ListNode를 새로 생성하지 않고 기존 노드를 활용하도록 수정했습니다. + +# list1의 노드 개수를 n, list2의 노드 개수를 m이라 할 때 +# 시간 복잡도: O(n + m) +# 공간 복잡도: O(1) -> dummy만 사용, 추가 공간 복잡도는 O(1) +class Solution_01: + def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: + # 맨 앞에 더미 노드를 하나 추가한다 + # 없는 상태로 짰는데 if node: else: 구문 늘어나서 맨 앞에 가상의 노드를 하나 추가해줬다 + dummy = ListNode(None) + node = dummy + + while True: + if not list1: # list1이 비어있으면 현재 노드 뒤로 list2를 이어준다. + node.next = list2 + break + + if not list2: # list2가 비어있으면 현재 노드 뒤로 list1을 이어준다. + node.next = list1 + break + + # 값을 비교해서 작은 값을 next 노드에 추가한다. + if list1.val <= list2.val: + node.next = list1 # 새로운 ListNode를 생성하지 않고 list1를 할당해준다. + list1 = list1.next # list1 하나 소비 + else: + node.next = list2 # 새로운 ListNode를 생성하지 않고 list2를 할당해준다. + list2 = list2.next # list2 하나 소비 + + # 다음 노드를 현재 노드로 할당해준다 + node = node.next + + return dummy.next + + +# 4. 예시 입력으로 호출 및 테스트 +# if __name__ == "__main__": +# list1 = make_linked_list([1, 2, 4]) +# list2 = make_linked_list([1, 3, 4]) + +# solution = Solution() +# merged_list = solution.mergeTwoLists(list1, list2) + +# print(merged_list) From f24511286b1f9519e87e5d64fdb19e3648658584 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Tue, 14 Jul 2026 00:55:53 +0900 Subject: [PATCH 2/9] 21. Merge Two Sorted Lists --- merge-two-sorted-lists/okyungjin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/merge-two-sorted-lists/okyungjin.py b/merge-two-sorted-lists/okyungjin.py index 3460b990ff..b1a704b56a 100644 --- a/merge-two-sorted-lists/okyungjin.py +++ b/merge-two-sorted-lists/okyungjin.py @@ -28,7 +28,7 @@ # list1의 노드 개수를 n, list2의 노드 개수를 m이라 할 때 # 시간 복잡도: O(n + m) -# 공간 복잡도: O(n + m) -> +# 공간 복잡도: O(n + m) class Solution_01: def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: # 맨 앞에 더미 노드를 하나 추가한다 @@ -69,7 +69,7 @@ def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> # list1의 노드 개수를 n, list2의 노드 개수를 m이라 할 때 # 시간 복잡도: O(n + m) # 공간 복잡도: O(1) -> dummy만 사용, 추가 공간 복잡도는 O(1) -class Solution_01: +class Solution: def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: # 맨 앞에 더미 노드를 하나 추가한다 # 없는 상태로 짰는데 if node: else: 구문 늘어나서 맨 앞에 가상의 노드를 하나 추가해줬다 From ea4170f829c699c3e1b3d5b9f1bd8fd903eba9b4 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 17:09:47 +0900 Subject: [PATCH 3/9] 104. Maximum Depth of Binary Tree --- maximum-depth-of-binary-tree/okyungjin.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 maximum-depth-of-binary-tree/okyungjin.py diff --git a/maximum-depth-of-binary-tree/okyungjin.py b/maximum-depth-of-binary-tree/okyungjin.py new file mode 100644 index 0000000000..9b9d25064f --- /dev/null +++ b/maximum-depth-of-binary-tree/okyungjin.py @@ -0,0 +1,28 @@ +# 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 + +# 시간 복잡도: O(N), 모든 노드를 한번 씩 방문 +# 공간 복잡도: O(N), 최악의 경우 모든 노드가 큐에 담길 수 있음 +class Solution: + def maxDepth(self, root: Optional[TreeNode]) -> int: + if root is None: + return 0 + + max_depth = 1 + queue = [(root, 1)] + + while queue: + node, cur_depth = queue.pop() + max_depth = max(cur_depth, max_depth) + + if node.left: + queue.append((node.left, cur_depth + 1)) + + if node.right: + queue.append((node.right, cur_depth + 1)) + + return max_depth From 441ac501a05c5c7e991e62eeb63dc7cbdc21622d Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 17:58:52 +0900 Subject: [PATCH 4/9] 153. Find Minimum in Rotated Sorted Array --- .../okyungjin.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 find-minimum-in-rotated-sorted-array/okyungjin.py diff --git a/find-minimum-in-rotated-sorted-array/okyungjin.py b/find-minimum-in-rotated-sorted-array/okyungjin.py new file mode 100644 index 0000000000..bbcdf18b9f --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/okyungjin.py @@ -0,0 +1,32 @@ +# [문제 분석] +# nums: 오름차순 정렬, 정수 배열, 중복 없음 +# 배열에서 가장 작은 수를 찾아 반환 +# 조건: O(log n)으로 작성할 것 + +# [접근법] +# 정렬된 배열이 주어지고, 배열이 n번 회전한다. 추세가 꺾이는 부분을 찾아 탐색 범위를 좁힌다. +# 배열이 정렬되어 있다는 조건이 있으므로 이진 탐색을 통해 탐색 범위를 좁혀 log n으로 탐색이 가능하다. + +# [복잡도] +# 시간 복잡도: O(log n), 이진 탐색을 하므로 log n +# 공간 복잡도: O(1) +class Solution: + def findMin(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] From d77d59d20fa9ef4935fedcf26b0872a6575ccf9a Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 18:43:58 +0900 Subject: [PATCH 5/9] 79. Word Search --- word-search/okyungjin.py | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 word-search/okyungjin.py diff --git a/word-search/okyungjin.py b/word-search/okyungjin.py new file mode 100644 index 0000000000..15c3a5ae07 --- /dev/null +++ b/word-search/okyungjin.py @@ -0,0 +1,52 @@ +# board: 영문 대/소문자 배열, m * n +# board의 상하좌우로 인접한 문자열을 이어붙여서 word를 완성할 수 있는지 여부를 반환한다. +# 단, 셀은 한번만 사용 가능하다 + +# dfs를 통해 백트랙킹으로 정답을 찾도록 구현했다. +# TODO: 시간/공간 복잡도 계산 +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + row_size = len(board) + col_size = len(board[0]) + + # 방문 여부를 기록하는 2차원 배열 + visited = [[False] * col_size for _ in range(row_size)] + + def dfs(row, col, str_idx) -> bool: + # 종료조건1: 보드의 좌표를 넘어가는 경우 + if row < 0 or row >= row_size or col < 0 or col >= col_size: + return False + + # 종료조건2: 이미 방문한 경우 + if visited[row][col]: + return False + + # 종료조건3: 문자열 불일치 + if board[row][col] != word[str_idx]: + return False + + # 정답 발견 시 종료 + if str_idx + 1 == len(word): + return True + + visited[row][col] = True + + # 차례대로 상, 하, 좌, 우의 좌표를 탐색 + found = dfs(row - 1, col, str_idx + 1) or \ + dfs(row + 1, col, str_idx + 1) or \ + dfs(row, col - 1, str_idx + 1) or \ + dfs(row, col + 1, str_idx + 1) + + visited[row][col] = False # 백트래킹 + + return found + + + # 시작점을 찾는다 + for r in range(row_size): + for c in range(col_size): + # board[r][c] == word[0] 인 시작점만 호출하도록 해서 최적화 + if board[r][c] == word[0] and dfs(r, c, 0): + return True + + return False From 9afa0f225c85b0ea06705e99e695ddee3c6f703c Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 20:02:57 +0900 Subject: [PATCH 6/9] 322. Coin Change --- coin-change/okyungjin.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 coin-change/okyungjin.py diff --git a/coin-change/okyungjin.py b/coin-change/okyungjin.py new file mode 100644 index 0000000000..9070ffca7f --- /dev/null +++ b/coin-change/okyungjin.py @@ -0,0 +1,37 @@ +# coins: 동전의 가격이 적힌 정수 배열, 각 숫자는 유니크함, 정렬에 대한 언급 X, (1 <= coins.length <= 12) +# amount: 돈의 총합 + +# amount를 만들 수 있는 가장 적은 동전의 수를 반환한다. +# coins로 amount를 만들 수 없는 경우 -1을 반환 +# 동전의 종류는 무한대라고 가정하고 문제를 풀 것 + +# 처음에는 greedy로 접근하려고 했는데, 금액이 큰 동전을 먼저 선택하는게 최소 동전의 수가 아니라서 dp로 풀이했다. + +# [복잡도] +# C: 코인의 개수, # A: amount +# 시간 복잡도: O(A * C) +# 공간 복잡도: O(A) +class Solution: + def coinChange(self, coins: List[int], amount: int) -> int: + NOT_POSSIBLE = amount + 1 + + # min_coins: 금액을 만드는데 필요한 동전 개수를 저장하는 배열 + # min_coins[i]: i원을 만드는데 필요한 최소 동전의 개수 + min_coins = [NOT_POSSIBLE] * (amount + 1) + min_coins[0] = 0 + + for cur_amount in range(1, amount + 1): + # coin: 선택한 동전 + for coin in coins: + if cur_amount >= coin: + # 둘 중 더 작은 값으로 업데이트 + # 1. 기존에 구한 개수 + # 2. 현재 동전을 1개 추가해서 만드는 개수 + min_coins[cur_amount] = min(min_coins[cur_amount], min_coins[cur_amount - coin] + 1) + + # 초기화된 값 그대로이면 불가능한 조합이므로 -1 반환 + if min_coins[amount] == NOT_POSSIBLE: + return -1 + # 최소 동전의 개수를 반환 + else: + return min_coins[amount] From e65811c991fc7c87af8f08050c9fe12823046734 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 20:26:14 +0900 Subject: [PATCH 7/9] =?UTF-8?q?79.=20Word=20Search=20(=EA=B3=B5=EA=B0=84?= =?UTF-8?q?=EB=B3=B5=EC=9E=A1=EB=8F=84=20=EC=B5=9C=EC=A0=81=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- word-search/okyungjin.py | 76 ++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/word-search/okyungjin.py b/word-search/okyungjin.py index 15c3a5ae07..84989c32aa 100644 --- a/word-search/okyungjin.py +++ b/word-search/okyungjin.py @@ -3,8 +3,11 @@ # 단, 셀은 한번만 사용 가능하다 # dfs를 통해 백트랙킹으로 정답을 찾도록 구현했다. -# TODO: 시간/공간 복잡도 계산 -class Solution: + +# L: word 의 길이 +# 시간 복잡도: O(m * n * 4^L) +# 공간 복잡도: O(m * n + L) +class SolutionA: def exist(self, board: List[List[str]], word: str) -> bool: row_size = len(board) col_size = len(board[0]) @@ -13,31 +16,77 @@ def exist(self, board: List[List[str]], word: str) -> bool: visited = [[False] * col_size for _ in range(row_size)] def dfs(row, col, str_idx) -> bool: + if str_idx == len(word): + return True + # 종료조건1: 보드의 좌표를 넘어가는 경우 if row < 0 or row >= row_size or col < 0 or col >= col_size: return False - # 종료조건2: 이미 방문한 경우 - if visited[row][col]: + # 종료조건 2: 이미 방문함 + # 종료조건 3: 문자열 불일치 + if visited[row][col] or board[row][col] != word[str_idx]: return False + + + visited[row][col] = True - # 종료조건3: 문자열 불일치 - if board[row][col] != word[str_idx]: - return False + # 차례대로 상, 하, 좌, 우의 좌표를 탐색 + found = (dfs(row - 1, col, str_idx + 1) or \ + dfs(row + 1, col, str_idx + 1) or \ + dfs(row, col - 1, str_idx + 1) or \ + dfs(row, col + 1, str_idx + 1)) - # 정답 발견 시 종료 - if str_idx + 1 == len(word): + visited[row][col] = False # 백트래킹 + + return found + + + # 시작점을 찾는다 + for r in range(row_size): + for c in range(col_size): + if board[r][c] == word[0] and dfs(r, c, 0): + return True + + return False + +# SolutionA 의 공간복잡도 최적화 버전, visited 제거 +# L: word 의 길이 +# 시간 복잡도: O(m * n * 4^L) +# 공간 복잡도: O(L) +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + VISITED_MARK = '#' + + row_size = len(board) + col_size = len(board[0]) + + def dfs(row, col, str_idx) -> bool: + if str_idx == len(word): return True + + # 종료조건1: 보드의 좌표를 넘어가는 경우 + if row < 0 or row >= row_size or col < 0 or col >= col_size: + return False + + # 종료조건 2: 이미 방문함 + # 종료조건 3: 문자열 불일치 + if board[row][col] == VISITED_MARK or board[row][col] != word[str_idx]: + return False + - visited[row][col] = True + # VISITED_MARK로 교체하여 방문을 기록 + origin_char = board[row][col] + board[row][col] = VISITED_MARK # 차례대로 상, 하, 좌, 우의 좌표를 탐색 - found = dfs(row - 1, col, str_idx + 1) or \ + found = (dfs(row - 1, col, str_idx + 1) or \ dfs(row + 1, col, str_idx + 1) or \ dfs(row, col - 1, str_idx + 1) or \ - dfs(row, col + 1, str_idx + 1) + dfs(row, col + 1, str_idx + 1)) - visited[row][col] = False # 백트래킹 + # 원본 문자열로 복원 + board[row][col] = origin_char return found @@ -45,7 +94,6 @@ def dfs(row, col, str_idx) -> bool: # 시작점을 찾는다 for r in range(row_size): for c in range(col_size): - # board[r][c] == word[0] 인 시작점만 호출하도록 해서 최적화 if board[r][c] == word[0] and dfs(r, c, 0): return True From b5c831784a35f428bcaedd88bca5a0c03817edf7 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 20:35:35 +0900 Subject: [PATCH 8/9] =?UTF-8?q?322.=20Coin=20Change=20(=EB=B0=98=EB=B3=B5?= =?UTF-8?q?=EB=AC=B8=20=EB=A1=9C=EC=A7=81=20=EC=B5=9C=EC=A0=81=ED=99=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coin-change/okyungjin.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/coin-change/okyungjin.py b/coin-change/okyungjin.py index 9070ffca7f..5941cb14e7 100644 --- a/coin-change/okyungjin.py +++ b/coin-change/okyungjin.py @@ -19,15 +19,21 @@ def coinChange(self, coins: List[int], amount: int) -> int: # min_coins[i]: i원을 만드는데 필요한 최소 동전의 개수 min_coins = [NOT_POSSIBLE] * (amount + 1) min_coins[0] = 0 + + # 최적화를 위해 정렬 + coins.sort() for cur_amount in range(1, amount + 1): - # coin: 선택한 동전 + # coin: 선택한 동전의 금액 for coin in coins: - if cur_amount >= coin: - # 둘 중 더 작은 값으로 업데이트 - # 1. 기존에 구한 개수 - # 2. 현재 동전을 1개 추가해서 만드는 개수 - min_coins[cur_amount] = min(min_coins[cur_amount], min_coins[cur_amount - coin] + 1) + # coins가 정렬되어 있으므로, cur_amount 보다 동전의 금액이 더 크면 이후는 확인 불필요 + if coin > cur_amount: + break + + # 둘 중 더 작은 값으로 업데이트 + # 1. 기존에 구한 개수 + # 2. 현재 동전을 1개 추가해서 만드는 개수 + min_coins[cur_amount] = min(min_coins[cur_amount], min_coins[cur_amount - coin] + 1) # 초기화된 값 그대로이면 불가능한 조합이므로 -1 반환 if min_coins[amount] == NOT_POSSIBLE: From 6808c867c0614697cb554ba9fd5bd1f2e9b50231 Mon Sep 17 00:00:00 2001 From: KyungJin Jung Date: Sat, 18 Jul 2026 21:01:56 +0900 Subject: [PATCH 9/9] =?UTF-8?q?104.=20Maximum=20Depth=20of=20Binary=20Tree?= =?UTF-8?q?=20(=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maximum-depth-of-binary-tree/okyungjin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/maximum-depth-of-binary-tree/okyungjin.py b/maximum-depth-of-binary-tree/okyungjin.py index 9b9d25064f..98a1a00f39 100644 --- a/maximum-depth-of-binary-tree/okyungjin.py +++ b/maximum-depth-of-binary-tree/okyungjin.py @@ -13,16 +13,16 @@ def maxDepth(self, root: Optional[TreeNode]) -> int: return 0 max_depth = 1 - queue = [(root, 1)] + stack = [(root, 1)] - while queue: - node, cur_depth = queue.pop() + while stack: + node, cur_depth = stack.pop() max_depth = max(cur_depth, max_depth) if node.left: - queue.append((node.left, cur_depth + 1)) + stack.append((node.left, cur_depth + 1)) if node.right: - queue.append((node.right, cur_depth + 1)) + stack.append((node.right, cur_depth + 1)) return max_depth