diff --git a/clone-graph/seungriyou.py b/clone-graph/seungriyou.py new file mode 100644 index 000000000..7d4332c60 --- /dev/null +++ b/clone-graph/seungriyou.py @@ -0,0 +1,82 @@ +# https://leetcode.com/problems/clone-graph/ + +# 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_dfs(self, node: Optional['Node']) -> Optional['Node']: + """ + [Complexity] + - TC: O(n + m) (n = node 개수, m = edge 개수) + - SC: O(n) (call stack & cache) + + [Approach] + {val: node} 형태의 dict를 캐시처럼 활용하여, DFS로 접근한다. + 각 node를 복제해야 하므로, 원본 node의 복제본을 O(1)에 lookup 하려면 dict에 key를 Node.val 값으로 설정해야 한다. + """ + copies = dict() # {val: node} + + if not node: + return None + + def copy_node(curr): + # base condition: 이미 copies에 존재하는 node라면 반환 + if curr.val in copies: + return copies[curr.val] + + # 현재 노드 복사 + copied_node = Node(val=curr.val) + + # copies에 추가 + copies[curr.val] = copied_node + + # neighbors를 순회하며, neighbors에 copy를 만들어 추가 + for ngbr in curr.neighbors: + copied_node.neighbors.append(copy_node(ngbr)) + + # 복사한 노드 반환 + return copied_node + + return copy_node(node) + + def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: + """ + [Complexity] + - TC: O(n + m) + - SC: O(n) (queue & cache) + + [Approach] + {val: node} 형태의 dict를 캐시처럼 활용하여, BFS로 접근한다. + """ + from collections import deque + + copies = dict() # {val: node} + + if not node: + return None + + q = deque([node]) + copied_root_node = Node(val=node.val) + copies[node.val] = copied_root_node + + while q: + curr = q.popleft() + + for ngbr in curr.neighbors: + # ngbr.val이 캐시에 존재하지 않으면, copy 후 캐시에 저장 + if ngbr.val not in copies: + # ngbr의 복사본 생성 및 캐시에 저장 + copies[ngbr.val] = Node(val=ngbr.val) + + # ngbr은 아직 방문되지 않았으므로, q에 추가 + q.append(ngbr) + + # curr 복사본의 neighbors에 ngbr 복사본 추가 + copies[curr.val].neighbors.append(copies[ngbr.val]) + + return copied_root_node diff --git a/longest-repeating-character-replacement/seungriyou.py b/longest-repeating-character-replacement/seungriyou.py new file mode 100644 index 000000000..599a147f6 --- /dev/null +++ b/longest-repeating-character-replacement/seungriyou.py @@ -0,0 +1,39 @@ +# https://leetcode.com/problems/longest-repeating-character-replacement/ + +class Solution: + def characterReplacement(self, s: str, k: int) -> int: + """ + [Complexity] + - TC: O(n) + - SC: O(1) (* s consists of only uppercase English letters) + + [Approach] + two pointer로 sliding window를 이동해가면서, k번 이내로 replace 했을 때 모두 같은 문자가 될 때의 max_len를 트래킹하면 된다. + 이때, 이 substring을 모두 같은 문자로 만들 수 있는 가장 작은 replacement 횟수를 구해 k와 비교해야 하는데, + 이 횟수 max_replace는 (substring의 길이 - 가장 빈도가 높은 문자의 등장 횟수) 이다. + max_replace가 k 이하라면 max_len을 업데이트하고, 아니라면 left를 한 칸 전진한다. + """ + from collections import defaultdict + + left = max_len = max_freq = 0 # left ~ right: k번 이내로 replace 했을 때, 모두 같은 문자일 때의 max_len 업데이트 + cnt = defaultdict(int) # left ~ right sliding window 내에서의 counter + + # right 한 칸씩 이동해가며 확인 + for right in range(len(s)): + # max_freq 업데이트 + cnt[s[right]] += 1 + max_freq = max(max_freq, cnt[s[right]]) + + # 현재 sliding window를 모두 같은 문자로 만들 수 있는 가장 작은 replacement 횟수 구하기 + sub_len = right - left + 1 + min_replace = sub_len - max_freq + + # min_replace가 k 이하이면, max_len 업데이트 + if min_replace <= k: + max_len = max(max_len, sub_len) + # 아니라면, left 한 칸 이동 + else: + cnt[s[left]] -= 1 + left += 1 + + return max_len diff --git a/reverse-bits/seungriyou.py b/reverse-bits/seungriyou.py new file mode 100644 index 000000000..115d1a9e2 --- /dev/null +++ b/reverse-bits/seungriyou.py @@ -0,0 +1,32 @@ +# https://leetcode.com/problems/reverse-bits/ + +class Solution: + def reverseBits_32(self, n: int) -> int: + """ + [Complexity] + - TC: O(32) + - SC: O(1) + + [Approach] + n의 맨 오른쪽 bit부터 res의 맨 왼쪽에 붙여나가기 + """ + res = 0 + for i in range(32): + res |= ((n >> i) & 1) << (31 - i) + return res + + def reverseBits(self, n: int) -> int: + """ + [Complexity] + - TC: O(16) + - SC: O(1) + + [Approach] + n의 바깥쪽에서부터 two pointer 처럼 res에 모으기 + """ + res = 0 + for i in range(16): + left = (n >> (31 - i)) & 1 + right = (n >> i) & 1 + res |= (left << i) | (right << (31 - i)) + return res