diff --git a/clone-graph/river20s.py b/clone-graph/river20s.py new file mode 100644 index 000000000..346ec5643 --- /dev/null +++ b/clone-graph/river20s.py @@ -0,0 +1,49 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = None): + self.val = val + self.neighbors = neighbors if neighbors is not None else [] +""" + +from typing import Optional +class Solution: + def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: + """ + Time Complexity: O(n + m) (n은 노드의 개수, m은 간선 개수) + Space Complexity: O(n) (노드 개수만큼 맵 사용) + """ + # clones_map 딕셔너리 + # key: 원본 노드 객체 + # value: 복제 노드 객체 + clones_map = {} # 노드를 복제 하고 바로 등록할 딕셔너리 + + def dfs_clone(original_node: Optional['Node']) -> Optional['Node']: + # 원본 노드가 비어있으면 None 반환 + if not original_node: + return None + + # 원본 노드가 clones_map에 있다면 + # 전에 복제 했음을 의미, 해당 복제 노드 객체를 반환 + if original_node in clones_map: + return clones_map[original_node] + + # 새로운 복제 노드 생성 후 val 복사 + new_clone = Node(original_node.val) + # 위에서 생성된 복제 노드를 clones_map에 등록 + clones_map[original_node] = new_clone + + # 원본 노드의 이웃을 복사 + if original_node.neighbors: + # 각각의 이웃 노드들에 대해 처리 + for original_neighbor in original_node.neighbors: + # 재귀적으로 dfs_clone 호출하여 clone + # (위 작업에 의해 이미 복제 했다면, 복제된 객체가 반환 될 것) + cloned_neighbor = dfs_clone(original_neighbor) + # 새로 복제된 노드 new_clone의 이웃으로 추가 + new_clone.neighbors.append(cloned_neighbor) + + return new_clone # 완성된 복제 노드 반환 + + # 시작 노드로부터 재귀적인 복제 시작 + return dfs_clone(node) diff --git a/longest-repeating-character-replacement/river20s.py b/longest-repeating-character-replacement/river20s.py new file mode 100644 index 000000000..d2de1ffd4 --- /dev/null +++ b/longest-repeating-character-replacement/river20s.py @@ -0,0 +1,41 @@ +class Solution: + def characterReplacement(self, s: str, k: int) -> int: + """ + Time Complexity: O(n) + Space Complexity: O(1) + """ + n = len(s) + + if n == 0: + return 0 + + left = 0 # 윈도우의 왼쪽 인덱스 (시작) + max_len = 0 # 가장 긴 유효한 부분 문자열 길이 + char_counts = {} # 현 윈도우 안에서 각 문자 빈도수 + max_freq_count = 0 # 현 윈도우 안에서 가장 많이 등장한 문자 빈도수 + + for right in range(n): + right_char = s[right] # 윈도우 오른쪽에 추가할 문자 + + # 추가할 문자 빈도수 갱신 + char_counts[right_char] = char_counts.get(right_char, 0) + 1 + + max_freq_count = max(max_freq_count, char_counts[right_char]) + + current_window_length = right - left + 1 + + # 바꿔야 하는 문자 수 = 윈도우 길이 - 가장 많은 문자의 빈도수 + changes_needed = current_window_length - max_freq_count + + # 만약 바꿔야 하는 문자 수가 k보다 크면 + # 유효하지 않은 윈도우 => 윈도우를 줄여야 함 + if changes_needed > k: + left_char = s[left] # 제거할 문자 + char_counts[left_char] -= 1 # 빈도수 줄이기 + + left += 1 # 윈도우 축소 + + # 최대 길이 업데이트, 반환 + max_len = max(max_len, right - left + 1) + + return max_len diff --git a/reverse-bits/river20s.py b/reverse-bits/river20s.py new file mode 100644 index 000000000..acd8a9479 --- /dev/null +++ b/reverse-bits/river20s.py @@ -0,0 +1,59 @@ +class Solution: + # -- follow up + # If this function is called many times, + # how would you optimize it? + # - 클래스 변수로 lookup table 만들어 + # - 8bits 단위로 미리 비트 뒤집은 테이블을 만들어두는 방법 + # _lookup_table_8bit = [0] * 256 + # for i in range(256): + # val = i + # rev_val = 0 + # for _ in range(8): # 8비트 뒤집기 + # rev_val = (rev_val << 1) | (val & 1) + # val >>= 1 + # _lookup_table_8bit[i] = rev_val + # def __init__(self): + # pass + + def reverseBits(self, n: int) -> int: + """ + Time Complexity: O(1) + Space Complexity: O(1) + - 항상 32번 연산하므로 O(1), + - 함수가 여러 번 호출되면 누적되어 성능 영향 줄 수도 있음 + -> reverseBits_lookupTable() 사용 + """ + reversed_n = 0 # 뒤집은 비트 저장 + num_bits = 32 + + for i in range(num_bits): + reversed_n <<= 1 + + if (n & 1) == 1: + reversed_n |= 1 + + n >>= 1 + + return reversed_n + + def reverseBits_lookupTable(self, n: int) -> int: + """ + Time Complexity: O(1) + Space Complexity: O(1) + - 룩업 테이블 생성 시 공간 필요 + - 하지만 최초 한 번만 필요하므로 + - 호출 누적되면 연산량은 더 적음 + """ + b0 = (n >> 0) & 0xFF + b1 = (n >> 8) & 0xFF + b2 = (n >> 16) & 0xFF + b3 = (n >> 24) & 0xFF + + rev_b0 = self._lookup_table_8bit[b0] + rev_b1 = self._lookup_table_8bit[b1] + rev_b2 = self._lookup_table_8bit[b2] + rev_b3 = self._lookup_table_8bit[b3] + + result = (rev_b0 << 24) | (rev_b1 << 16) | (rev_b2 << 8) | rev_b3 + + return result