diff --git a/week-08/combination-sum/ImTotem.py.md b/week-08/combination-sum/ImTotem.py.md new file mode 100644 index 0000000..1f44246 --- /dev/null +++ b/week-08/combination-sum/ImTotem.py.md @@ -0,0 +1,46 @@ +# Intuition + +평범한 백트래킹 문제다. + +# Approach + +1. 숫자들을 정렬한다. +2. 백트래킹으로 조합을 찾는다. +3. 각 재귀 호출에서: + - 목표 값이 0이 되면 현재 조합을 결과에 추가한다. + - 현재 인덱스부터 시작하여 가능한 모든 후보 숫자를 시도한다. + - 숫자가 현재 목표보다 크면 반복을 중단한다. + +# Complexity +- Time complexity: $$O(2^N)$$ + +- Space complexity: $$O(T)$$ + - T는 목표 값(target) + - 재귀 호출의 최대 깊이는 `target/min(candidates)` + +# Code +```python +class Solution: + def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + candidates.sort() + + n = len(candidates) + ans = [] + + stack = [] + def dfs(target, idx): + if target == 0: + ans.append(stack[:]) + + for i in range(idx, n): + if candidates[i] > target: break + + stack.append(candidates[i]) + dfs(target - candidates[i], i) + stack.pop() + + dfs(target, 0) + + return ans +``` + diff --git a/week-08/construct-binary-tree-from-preorder-and-inorder-traversal/ImTotem.py.md b/week-08/construct-binary-tree-from-preorder-and-inorder-traversal/ImTotem.py.md new file mode 100644 index 0000000..393ba19 --- /dev/null +++ b/week-08/construct-binary-tree-from-preorder-and-inorder-traversal/ImTotem.py.md @@ -0,0 +1,51 @@ +# Intuition + +모르곘어서 풀이를 봤다. 트리 탐색 어렵다... + +# Approach + +1. 중위 순회 배열의 값과 인덱스를 매핑하는 딕셔너리를 생성한다. 이를 통해 루트 노드의 위치를 빠르게 찾을 수 있다. +2. 전위 순회 배열을 deque로 변환하여 효율적으로 왼쪽 pop 연산을 수행할 수 있도록 한다. +3. 재귀 함수 build를 정의하여 트리를 구성한다: + - 현재 범위의 시작과 끝 인덱스를 매개변수로 받는다. + - 전위 순회 배열에서 첫 번째 요소를 pop하여 현재 노드로 사용한다. + - 중위 순회에서 현재 노드의 위치를 찾아 왼쪽과 오른쪽 서브트리의 범위를 결정한다. + - 재귀적으로 왼쪽과 오른쪽 서브트리를 구성한다. +4. 구성된 루트 노드를 반환한다. + +# Complexity +- Time complexity: $$O(N)$$ + - n은 노드의 수. 각 노드를 한 번씩 방문하므로 $O(N)$. + +- Space complexity: $$O(N)$$ + - 중위 순회 배열의 값과 인덱스를 매핑하는 딕셔너리에 $O(N)$ 공간이 필요. + - 재귀 호출 스택의 최대 깊이는 트리의 높이와 같으며, 최악의 경우 $O(N)$이 될 수 있음. + +# Code +```python +# 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 Solution: + def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: + mapping = {inorder[i]:i for i in range(len(inorder))} + + preorder = collections.deque(preorder) + + def build(start, end): + if start > end: return None + + root = TreeNode(preorder.popleft()) + mid = mapping[root.val] + + root.left = build(start, mid - 1) + root.right = build(mid + 1, end) + + return root + + return build(0, len(preorder) - 1) +``` + diff --git a/week-08/implement-trie-prefix-tree/ImTotem.py.md b/week-08/implement-trie-prefix-tree/ImTotem.py.md new file mode 100644 index 0000000..7a211ee --- /dev/null +++ b/week-08/implement-trie-prefix-tree/ImTotem.py.md @@ -0,0 +1,78 @@ +# Intuition + +Trie 자료구조가 뭔지 몰라서 찾아봤다. 뭔지 알고나니까 쉬운거 같다. + +# Approach + +1. 초기화 (`__init__`): + - 루트 노드를 빈 딕셔너리로 초기화한다. +2. 삽입 (`insert`): + - 단어의 각 문자를 트리에 순차적으로 추가한다. + - 각 문자는 딕셔너리의 키로 표현된다. + - 단어의 끝을 표시하기 위해 특별한 키 ';'를 사용한다. +3. 검색 (`search`): + - 주어진 단어의 각 문자를 트리에서 순차적으로 찾는다. + - 모든 문자를 찾고 마지막에 ';' 키가 있으면 단어가 존재하는 것이다. +4. 접두사 검색 (`startsWith`): + - 주어진 접두사의 각 문자를 트리에서 순차적으로 찾는다. + - 모든 문자를 찾을 수 있으면 해당 접두사로 시작하는 단어가 존재하는 것이다. + +# Complexity +- Time complexity: + - Insert: $$O(N)$$ + - Search: $$O(N)$$ + - N은 단어의 길이 + + +- Space complexity: + - Insert: $$O(N)$$ + - Search: $$O(1)$$ + - N은 단어의 길이 + +# Code +```python +class Trie: + + def __init__(self): + self.root = dict() + + def insert(self, word: str) -> None: + head = self.root + + for c in word: + if c not in head: + head[c] = dict() + + head = head[c] + + head[';'] = None + + def search(self, word: str) -> bool: + head = self.root + + for c in word: + if c not in head: + return False + head = head[c] + + return ';' in head + + def startsWith(self, prefix: str) -> bool: + head = self.root + + for c in prefix: + if c not in head: + return False + + head = head[c] + + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) +``` + diff --git a/week-08/kth-smallest-element-in-a-bst/ImTotem.py.md b/week-08/kth-smallest-element-in-a-bst/ImTotem.py.md new file mode 100644 index 0000000..f751d72 --- /dev/null +++ b/week-08/kth-smallest-element-in-a-bst/ImTotem.py.md @@ -0,0 +1,42 @@ +# Intuition + +BST의 중위 순회(inorder traversal)는 원소를 오름차순으로 방문하는 특성을 이용한다. + +# Approach + +1. 스택을 사용하여 반복적 중위 순회를 구현한다. +2. 루트에서 시작하여 왼쪽 자식 노드들을 모두 스택에 넣는다. +3. 스택에서 노드를 꺼내 처리한다 (이는 현재 가장 작은 미방문 노드). +4. k를 1 감소시키고, k가 0이 되면 현재 노드의 값을 반환한다. +5. 오른쪽 자식 노드로 이동하여 과정을 반복한다. + +# Complexity +- Time complexity: $$O(N)$$ + +- Space complexity: $$O(H)$$ + - H는 트리의 높이 + +# Code +```python +# 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 Solution: + def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: + stack = [] + + while True: + while root: + stack.append(root) + root = root.left + root = stack.pop() + k -= 1 + if not k: + return root.val + root = root.right + +``` + diff --git a/week-08/word-search/ImTotem.py.md b/week-08/word-search/ImTotem.py.md new file mode 100644 index 0000000..9eb67d3 --- /dev/null +++ b/week-08/word-search/ImTotem.py.md @@ -0,0 +1,59 @@ +# Intuition + +평범한 dfs 문제다. 였으나 뇌빼고 풀다가 오래걸렸다. + +# Approach + +1. 보드의 모든 셀을 시작점으로 하여 DFS를 수행한다. +2. DFS 에서 다음을 확인한다: + - 현재 위치가 보드 범위 내에 있는지 + - 현재 셀의 문자가 찾고 있는 단어의 현재 인덱스의 문자와 일치하는지 + - 단어의 모든 문자를 찾았는지 (종료 조건) +3. 현재 셀을 방문했음을 표시하기 위해 임시로 값을 제거한다. +4. 상하좌우 네 방향으로 DFS를 재귀적으로 수행한다. +5. 백트래킹을 위해 셀의 원래 값을 복구한다. + +# Complexity +- Time complexity: $$O(M \times N \times 4^L)$$ + - M, N은 보드의 크기, L은 단어의 길이 + +- Space complexity: $$O(N)$$ + - N은 단어의 길이 + +# Code +```python +class Solution: + def exist(self, board: List[List[str]], word: str) -> bool: + m, n = len(board), len(board[0]) + + d = [0, 1, 0, -1, 0] + + def dfs(x, y, idx): + if not (0 <= x < n and 0 <= y < m): + return False + + if board[y][x] != word[idx]: + return False + + if len(word)-1 == idx: + return True + + tmp, board[y][x] = board[y][x], '' + + for i in range(4): + if dfs(x+d[i], y+d[i+1], idx+1): + return True + + board[y][x] = tmp + + return False + + for i in range(m): + for j in range(n): + if dfs(j, i, 0): + return True + + return False + +``` +