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
43 changes: 43 additions & 0 deletions coin-change/okyungjin.py
Comment thread
okyungjin marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Dynamic Programming
  • 설명: 금액(amount)을 만들기 위한 최소 동전 수를 DP 배열로 관리하며, 각 금액에 대해 모든 동전을 사용해 최적 값을 갱신하는 전형적인 동적계획(Dynamic Programming) 풀이이다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(A * C) O(A * C)
Space O(A) O(A)

피드백: 금액별로 모든 동전을 시도해 최소값을 갱신하는 DP 풀이로 문제의 조건에 맞는 최단 동전 수를 구한다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# 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

# 최적화를 위해 정렬
coins.sort()

for cur_amount in range(1, amount + 1):
# coin: 선택한 동전의 금액
for coin in coins:
# 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:
return -1
# 최소 동전의 개수를 반환
else:
return min_coins[amount]
32 changes: 32 additions & 0 deletions find-minimum-in-rotated-sorted-array/okyungjin.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Binary Search
  • 설명: 정렬된 배열이 회전되었을 때 최소값을 찾기 위해 중간값과 양 끝 값을 비교해 탐색 범위를 반으로 줄이는 이진 탐색 패턴을 사용한다. 시간 복잡도 O(log n)으로 풀이한다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(log n) O(log n)
Space O(1) O(1)

피드백: 정렬된 배열이 회전되었을 때 중간값과 끝 값을 비교해 탐색 범위를 절단한다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -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]
28 changes: 28 additions & 0 deletions maximum-depth-of-binary-tree/okyungjin.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@DaleStudy 내가 의도한 유형으로 안 풀었어?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

의도한 유형에 맞춰 풀었는지 확인해 드릴게요.

  • 문제별 의도: 흔히 요구하는 풀이형태(대표적으로 이진 탐색으로 최소값 찾기, BFS/DFS로 트리/그래프 탐색, 연결 리스트 병합 등)와 시간/공간 복잡도까지 명시된 주석이 포함되어 있습니다.
  • PR에 담긴 변경 사항은 각 문제의 표준 풀이 흐름에 따라 구현되어 있습니다. 확인 포인트:
    • findMin: 이진 탐색으로 최소값 찾기(O(log n))에 맞게 구현되어 있습니다.
    • maxDepth: BFS 방식으로 최대 깊이 구하기(O(N))가 맞습니다.
    • mergeTwoLists: 연결 리스트를 한 방향으로 병합하는 풀이가 두 버전으로 포함되어 있으며, 두 버전 모두 시간복잡도 O(n+m)로 적절합니다. 추가로 공간 복잡도 O(1) 버전도 포함되어 있고, 기존 노드 재활용 여부도 처리되어 있습니다.
    • word-search: DFS + 백트래킹으로 단어 탐색하는 기본 해법이 구현되어 있습니다.
  • 의도와 부합 여부:
    • 모두 표준 풀이 방향에 맞춰 구현되었습니다.
    • 각 파일에 문제 분석, 접근법, 시간/공간 복잡도 코멘트가 포함되어 있어 의도대로 문서화도 되어 있습니다.
    • 다만 각 문제의 테스트나 실제 호출부(main) 없이 솔루션 클래스만 포함된 부분이 있어 PR 설명에 테스트 예제가 필요하면 보완하면 좋습니다.

정리: 의도한 유형(표준 솔루션 + 로그/선언적 복잡도 표기)에 대체로 부합합니다. 테스트 예제나 간단한 검증 코드가 있으면 더 확실해질 거예요.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Depth-First Search, Binary Search
  • 설명: 주어진 코드는 스택을 이용한 깊이 우선 탐색(DFS)으로 트리를 순회하며 최대 깊이를 계산한다. 재귀 대신 명시적 스택으로 노드를 방문해 깊이를 추적하는 패턴이다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(N) O(n)
Space O(N) O(h)

피드백: 스택을 사용해 각 노드의 깊이를 관리하여 전체 트리를 탐색한다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -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
stack = [(root, 1)]

while stack:
node, cur_depth = stack.pop()
max_depth = max(cur_depth, max_depth)

Comment on lines +15 to +21

@ICE0208 ICE0208 Jul 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

현재 구현은 LIFO 방식으로 동작하므로, 변수 이름도 queue보다 stack이 자연스러울 것 같습니다!

반대로 FIFO 방식의 큐로 구현한다면 노드가 깊이 순서대로 처리되므로, max()를 사용하지 않고 max_depth = cur_depth로 갱신하는 것만으로도 충분할 것 같습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@ICE0208 놓친 부분 짚어주셔서 감사합니다!

@okyungjin okyungjin Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

stack으로 변수명 수정했습니다(6808c86)

감사합니다!

if node.left:
stack.append((node.left, cur_depth + 1))

if node.right:
stack.append((node.right, cur_depth + 1))

return max_depth
110 changes: 110 additions & 0 deletions merge-two-sorted-lists/okyungjin.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@DaleStudy 개선 제안: 더 나은 변수 네이밍과 주석 정리로 가독성을 높일 수 있습니다. 는 어떤 방식을 말하는건지 제안해주라

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

좋은 제안이에요. 더 나은 변수 네이밍과 주석 정리는 코드 가독성과 유지보수에 큰 도움이 됩니다. 아래 방식으로 구체적으로 제안드립니다.

  1. 변수 네이밍 가이드
  • 리스트 노드 포인터: current, tail, curr, prev 등 일관된 이름 사용
  • 리스트 구간 구분자: l1, l2 대신 list1, list2처럼 의미 명시
  • 비교 대상 값: val1, val2처럼 어떤 값을 가리키는지 명확히
  • 결과물 포인터: merged, tail, head 같은 직관적 이름
  • 반복 상태: while_head, end_condition처럼 상태를 나타내는 이름은 피하고 직관적으로
  1. 주석 정리 원칙
  • 함수/메서드에 한 줄 요약: 무엇을 하는지 간단 명확히
  • 매 분기점 주석 최소화: 코드가 자명할 때는 불필요한 주석 제거
  • 비효율/특수 처리 구간에만 설명
  • 복잡도 표시는 별도 주석으로 보존
  • 불가피한 리스트 교체나 포인터 변경 시 왜 그런 선택을 했는지 이유 기재
  1. 구체적 적용 예시
  • 예시 변수명: l1, l2 대신 list1, list2 유지하고, curr 대신 tail로 통일
  • 주석 예시:
    • 함수 설명: "두 연결 리스트를 오름차순으로 병합하고, 새로운 노드를 추가하지 않고 기존 노드를 재배치한다."
    • 루프 조건: "리스트 중 하나가 소진되면 남은 노드를 끝에 연결한다."
  1. 코드 스타일 가이드라인
  • 중복 주석 제거: 같은 내용을 반복하는 주석 제거
  • 필요 시 docstring 활용: 함수시그니처 바로 아래에 간단한 설명 작성
  • 타입 힌트 유지: Optional[ListNode] 등의 타입은 유지

원하는 방향으로 샘플 리팩틴 코드도 같이 드릴게요.

Comment thread
okyungjin marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Two Pointers, Monotonic Stack, Hash Map / Hash Set
  • 설명: 두 정렬 리스트를 순차적으로 비교하며 작은 값을 연결하는 방식으로 문제를 풀이한다. 포인터를 두 개 사용해 서로의 노드를 탐색하는 전형적인 Two Pointers 패턴이다. 또한 더미 노드를 활용해 구현을 간단하게 만드는 점은 구현 기법에 해당한다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(n + m) O(n + m)
Space O(1) O(1)

피드백: 둘 다 선형 시간복잡도로 병합하며, 메모리 사용은 노드 재사용 여부에 따라 달라진다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이 부분에서 ListNode(list1.val)로 매번 새 노드를 생성하시는데, 기존 노드를 그대로 연결(node.next = list1)하면 새 노드를 안 만들어도 돼서 공간 복잡도를 O(1)로 줄일 수 있을 것 같아요. 저는 그렇게 풀었는데 참고하시라고 남깁니다! 전체 로직은 깔끔하게 잘 읽혔어요 👍

@okyungjin okyungjin Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@chapse57 코멘트 감사합니다! 풀이를 2가지로 작성했는데 이 부분 언급해주신게 맞을까요?

https://github.com/okyungjin/leetcode-study/blob/f24511286b1f9519e87e5d64fdb19e3648658584/merge-two-sorted-lists/okyungjin.py#L72-L99

# 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:
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)
100 changes: 100 additions & 0 deletions word-search/okyungjin.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@DaleStudy 시간 복잡도랑 공간 복잡도 어떻게 계산했어? 과정 알려줘

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

다음 코드들에서 대표적으로 다루는 두 문제의 시간/공간 복잡도 계산 방법을 정리해 드립니다.

  1. find-minimum-in-rotated-sorted-array (이진 탐색)
  • 시간 복잡도: O(log n)
    • 배열의 중간값과 경계(right)를 비교해 추세가 꺾이는지 확인하며 탐색 구간을 반으로 줄입니다.
    • 구간 크기가 매 iterations마다 절반으로 감소하므로 총 반복 횟수는 log2(n)에 비례합니다.
  • 공간 복잡도: O(1)
    • 추가적인 자료구조 없이 좌/오른쪽 인덱스 변수(left, right)만 사용합니다.
  1. maximum-depth-of-binary-tree (너비 우선 탐색/큐 이용 예시)
  • 시간 복잡도: O(N)
    • 트리의 모든 노드를 한 번씩 방문합니다.
  • 공간 복잡도: O(N) (최악의 경우)
    • 큐에 동시에 저장될 노드의 최대 개수에 비례합니다. 최악의 경우 트리의 높이가 N인 skewed 트리에서 큐 크기가 O(N)이 됩니다.
  1. merge-two-sorted-lists (링크드 리스트 병합)
  • 시간 복잡도: O(n + m)
    • list1과 list2의 모든 노드를 한 번씩 비교하며 새 노드를 연결합니다.
  • 공간 복잡도:
    • 솔루션 1은 새 노드 생성으로 O(n + m) 추가 공간.
    • 최종 구현은 기존 노드를 연결하는 방식으로 O(1) 추가 공간(Dummy 노드 포함)으로 간주합니다. 즉, 추가 배열/리스트 없이 포인터만 사용하므로 O(1) 추가 공간이 일반적입니다.
  1. word-search (DFS + 백트래킹)
  • 시간 복잡도: 최악의 경우 O(m * n * 4^L)
    • m×n개의 시작점에서 DFS가 최대 길이 L(word의 길이)까지 탐색하며, 각 위치에서 최대 4방향으로 분기합니다.
    • 이때 경로 중복 방문을 막기 위해 방문 표시를 사용하지만, 최악의 경우 지수적으로 탐색할 수 있습니다.
  • 공간 복잡도: O(L) 재귀 스택
    • 재귀 깊이가 단어의 길이 L에 비례합니다. 추가로 방문 기록 배열은 O(mn) 공간이 필요합니다.

추가 팁

  • 정확한 상수까지 포함한 분석은 구현에 따라 달라집니다. 예를 들어 DFS에서 방문 배열의 초기화 비용이나, 이진 탐색의 중간값 비교 횟수 등을 고려하면 미세한 차이가 있습니다.
  • 주석에 명시한 입력 크기(n, m, L 등)와 함께 위의 표현식으로 정리하면 일관된 비교가 됩니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@dalstudy word-search 프루닝 어떻게 하면 더 좋을지 제안해주라. 해시맵으로 문자열의 좌표를 미리 기록해두기?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

DFS를 시작하기 전에 단어의 길이가 보드 전체 칸 수보다 긴지 확인하면, 경로를 만들 수 없는 입력을 탐색 전에 바로 제외할 수 있을 것 같습니다!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

좋은 의견 감사합니다!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

  • 패턴: Depth-First Search, Backtracking, Hash Map / Hash Set
  • 설명: DFS를 이용한 탐색과 백트래킹으로 각 문자 매칭 시 분기점을 따라 보드를 탐색한다. 중복 방문 방지를 위해 방문 표를 사용하거나 문자열 대체로 백트래킹을 구현한다.

📊 시간/공간 복잡도 분석

유저 분석 실제 분석 결과
Time O(m * n * 4^L) O(m * 4^L)
Space O(L) O(L)

피드백: SolutionA는 방문 배열을 사용하고, Solution은 보드를 직접 마킹해 공간을 절약한다.

개선 제안: 현재 구현이 적절해 보입니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# board: 영문 대/소문자 배열, m * n
# board의 상하좌우로 인접한 문자열을 이어붙여서 word를 완성할 수 있는지 여부를 반환한다.
# 단, 셀은 한번만 사용 가능하다

# dfs를 통해 백트랙킹으로 정답을 찾도록 구현했다.

# 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])

# 방문 여부를 기록하는 2차원 배열
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: 이미 방문함
# 종료조건 3: 문자열 불일치
if visited[row][col] or board[row][col] != word[str_idx]:
return False


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):
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_MARK로 교체하여 방문을 기록
origin_char = board[row][col]
board[row][col] = VISITED_MARK

# 차례대로 상, 하, 좌, 우의 좌표를 탐색
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))

# 원본 문자열로 복원
board[row][col] = origin_char

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
Loading