diff --git a/linked-list-cycle/seungriyou.py b/linked-list-cycle/seungriyou.py
new file mode 100644
index 000000000..2c94a8aa3
--- /dev/null
+++ b/linked-list-cycle/seungriyou.py
@@ -0,0 +1,55 @@
+# https://leetcode.com/problems/linked-list-cycle/
+
+from typing import Optional
+
+# Definition for singly-linked list.
+class ListNode:
+    def __init__(self, x):
+        self.val = x
+        self.next = None
+
+class Solution:
+    def hasCycle_on(self, head: Optional[ListNode]) -> bool:
+        """
+        [Complexity]
+            - TC: O(n)
+            - SC: O(n)
+
+        [Approach]
+            hash table로 visited 노드를 기록한다.
+        """
+        curr = head
+        visited = set()
+
+        while curr:
+            if curr in visited:
+                return True
+
+            visited.add(curr)
+            curr = curr.next
+
+        return False
+
+    def hasCycle(self, head: Optional[ListNode]) -> bool:
+        """
+        [Complexity]
+            - TC: O(n)
+            - SC: O(1)
+
+        [Approach]
+            Floyd’s Cycle Detection 알고리즘을 사용한다.
+            linked list에서 slow (1칸씩 전진) & fast (2칸씩 전진) runner를 이용하면,
+                - slow와 fast가 만난다면 cyclic
+                - 만나지 않은 채로 fast가 끝에 도달하면 not cyclic
+            이다.
+        """
+        slow = fast = head
+
+        while fast and fast.next:
+            slow = slow.next
+            fast = fast.next.next
+
+            if slow == fast:
+                return True
+
+        return False
diff --git a/maximum-product-subarray/seungriyou.py b/maximum-product-subarray/seungriyou.py
new file mode 100644
index 000000000..980c4f303
--- /dev/null
+++ b/maximum-product-subarray/seungriyou.py
@@ -0,0 +1,38 @@
+# https://leetcode.com/problems/maximum-product-subarray/
+
+from typing import List
+
+class Solution:
+    def maxProduct(self, nums: List[int]) -> int:
+        """
+        [Complexity]
+            - TC: O(n)
+            - SC: O(1)
+
+        [Approach]
+            nums를 순회하며 현재 보고 있는 값 num이 포함되는 max subarray product를 구하기 위해서는
+            max(이전 값과 연속되는 subarray인 경우, 이전 값과 연속되지 않는 subarray인 경우)를 구해야 한다.
+                - num이 양수일 때: max(이전까지의 max subarray product * num, num)
+                - num이 음수일 때: max(이전까지의 min subarray product * num, num)
+            따라서 매 단계마다 이전까지의 max subarray product(= max_p)와 min subarray product(= min_p)를 트래킹해야 한다.
+        """
+        res = max_p = min_p = nums[0]
+
+        for i in range(1, len(nums)):
+            num = nums[i]
+
+            # 1. num이 음수라면, max_p와 min_p 바꿔치기
+            # if num < 0:
+            #     max_p, min_p = min_p, max_p
+
+            # 2. max_p, min_p 업데이트
+            # max_p = max(max_p * num, num)
+            # min_p = min(min_p * num, num)
+
+            # 1 & 2번 대신, 다중 할당으로 처리 가능
+            max_p, min_p = max(max_p * num, min_p * num, num), min(max_p * num, min_p * num, num)
+
+            # 3. res 값 업데이트
+            res = max(res, max_p)
+
+        return res
diff --git a/minimum-window-substring/seungriyou.py b/minimum-window-substring/seungriyou.py
new file mode 100644
index 000000000..26a75842c
--- /dev/null
+++ b/minimum-window-substring/seungriyou.py
@@ -0,0 +1,114 @@
+# https://leetcode.com/problems/minimum-window-substring/
+
+class Solution:
+    def minWindow1(self, s: str, t: str) -> str:
+        """
+        [Complexity]
+            - TC: O(m * k + n) (k = is_included() = len(set(t)))
+            - SC: O(k) (res 제외)
+
+        [Approach]
+            다음과 같은 counter를 유지하며, two pointer로 window를 이동하며 min window substring을 트래킹한다.
+                - 생성 시) t의 모든 문자에 대해 ++
+                - pointer 이동 시) window에 포함되는 문자 중 t에 속하는 문자에 대해 --
+        """
+        from collections import Counter
+
+        # early stop
+        m, n = len(s), len(t)
+        if m < n:
+            return ""
+
+        # t에 대한 counter 생성
+        counter = Counter(t)
+
+        # t의 모든 문자가 window에 포함되는지 확인하는 함수
+        def is_included():
+            # counter의 모든 값이 0 이하이면, t의 모든 문자가 window에 포함되는 것 (중복 포함)
+            return all(c <= 0 for c in counter.values())
+
+        lo, min_len = 0, 1e6
+        res = ""
+
+        for hi in range(m):
+            # 현재 window에 포함된 문자를 counter에 반영
+            if s[hi] in counter:
+                counter[s[hi]] -= 1
+
+            # t의 모든 문자가 window에 포함되어있다면(= counter의 모든 값이 <= 0이면),
+            # counter 값이 음수 ~ 0이 될 때까지 lo 증가시키면서 (min window를 구해야하므로) counter 업데이트
+            if is_included():
+                while True:
+                    # window의 첫 번째 문자가 t에 속하는 문자라면
+                    if s[lo] in counter:
+                        # counter에서의 값이 0이면, 더이상 lo를 오른쪽으로 줄일 수 없음
+                        if counter[s[lo]] == 0:
+                            break
+                        # coutner에서의 값이 음수라면, lo를 오른쪽으로 줄일 수 있으므로 counter 반영
+                        else:
+                            counter[s[lo]] += 1
+                    # lo를 오른쪽으로 한 칸 이동
+                    lo += 1
+
+            # (1) t의 모든 문자가 window에 포함되어 있고 (2) 현재 window의 length가 min_len 보다 작다면
+            # window substring 업데이트
+            if is_included() and (new_len := hi - lo + 1) < min_len:
+                min_len = new_len
+                res = s[lo:hi + 1]
+
+        return res
+
+    def minWindow(self, s: str, t: str) -> str:
+        """
+        [Complexity]
+            - TC: O(m + n)
+            - SC: O(k)
+
+        [Approach]
+            1) 위의 풀이에서 is_included()를 실행하는 데에 O(k)이 소요되므로,
+               (t에 속하는 문자 중, 아직 window에 모두 포함되지 않은 문자 종류 개수)를 트래킹하는 변수 remains를 이용하여 최적화 한다.
+               즉, remains == 0이라면 is_included()인 것과 동일하다.
+            2) 반복문 안에서 문자열 슬라이싱으로 res를 업데이트 할 때 추가적인 복잡도가 소요된다.
+               따라서 min window에 대한 pointer인 min_lo, min_hi만 트래킹하고, return 문에서 문자열 슬라이싱으로 반환한다.
+               단, min window substring이 존재하지 않는다면 결과가 빈 문자열이 될 수 있으므로, min_lo ~ min_hi - 1 범위를 반환하도록 한다.
+        """
+        from collections import Counter
+
+        # early stop
+        m, n = len(s), len(t)
+        if m < n:
+            return ""
+
+        # t에 대한 counter 생성
+        counter = Counter(t)
+
+        # counter의 값을 모두 확인하는 is_include() 최적화
+        remains = len(counter)  # t에 속하는 문자 중, 아직 window에 모두 포함되지 않은 문자 종류 개수
+        lo = min_lo = min_hi = 0
+        min_len = m + 1
+
+        for hi in range(m):
+            # 현재 window에 포함된 문자를 counter에 반영
+            if s[hi] in counter:
+                counter[s[hi]] -= 1
+                # 현재 window에 해당 문자가 t에 존재하는 개수만큼 들어와있다면, remains--
+                if counter[s[hi]] == 0:
+                    remains -= 1
+
+            # t의 모든 문자가 window에 포함되어있는 동안 lo 이동
+            while not remains:
+                # 최소 길이 window substring 갱신
+                if (new_len := hi - lo + 1) < min_len:
+                    min_len, min_lo, min_hi = new_len, lo, hi + 1
+
+                # lo 이동 전, counter 업데이트
+                if s[lo] in counter:
+                    counter[s[lo]] += 1
+                    # counter의 값이 0 초과가 된다면, 더이상 window에 해당 문자가 모두 들어있지 않다는 것이므로 remains++
+                    if counter[s[lo]] > 0:
+                        remains += 1
+
+                # lo를 오른쪽으로 한 칸 이동
+                lo += 1
+
+        return s[min_lo:min_hi]
diff --git a/pacific-atlantic-water-flow/seungriyou.py b/pacific-atlantic-water-flow/seungriyou.py
new file mode 100644
index 000000000..92bdc120d
--- /dev/null
+++ b/pacific-atlantic-water-flow/seungriyou.py
@@ -0,0 +1,97 @@
+# https://leetcode.com/problems/pacific-atlantic-water-flow/
+
+from typing import List
+
+class Solution:
+    def pacificAtlantic_bfs(self, heights: List[List[int]]) -> List[List[int]]:
+        """
+        [Complexity]
+            - TC: O(m * n) (모든 칸은 최대 한 번씩 방문)
+            - SC: O(m * n) (queue)
+
+        [Approach]
+            거꾸로 각 바다에 맞닿아있는 edges에서부터 시작해서, BFS로 height 값이 gte인 칸(-> 바다에서부터 거꾸로 확인하므로)을 방문하며 기록한다.
+            pacific & atlantic 쪽 edges에서 시작해서 방문한 칸들의 교집합을 구하면 된다.
+        """
+        from collections import deque
+
+        m, n = len(heights), len(heights[0])
+        dr, dc = [-1, 1, 0, 0], [0, 0, -1, 1]
+
+        def bfs(start_cells):
+            q = deque(start_cells)
+            visited = set(start_cells)
+
+            while q:
+                r, c = q.popleft()
+
+                for i in range(4):
+                    nr, nc = r + dr[i], c + dc[i]
+
+                    if (
+                            0 <= nr < m and 0 <= nc < n  # valid한 범위 확인
+                            and (nr, nc) not in visited  # 방문 여부 확인
+                            and heights[nr][nc] >= heights[r][c]  # height 값이 현재 칸보다 gte인지 확인 (** 거꾸로 확인하므로)
+                    ):
+                        q.append((nr, nc))
+                        visited.add((nr, nc))
+
+            return visited
+
+        # pacific & atlantic 쪽 edges 모으기
+        edges_p, edges_a = [], []
+        for r in range(m):
+            edges_p.append((r, 0))
+            edges_a.append((r, n - 1))
+        for c in range(n):
+            edges_p.append((0, c))
+            edges_a.append((m - 1, c))
+
+        # edges로부터 BFS로 방문
+        visited_p = bfs(edges_p)
+        visited_a = bfs(edges_a)
+
+        # pacific과 atlantic의 교집합 반환
+        return [list(cell) for cell in visited_p & visited_a]
+
+    def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
+        """
+        [Complexity]
+            - TC: O(m * n) (모든 칸은 최대 한 번씩 방문)
+            - SC: O(m * n) (call stack)
+
+        [Approach]
+            BFS 풀이를 DFS로도 접근 가능하다.
+        """
+        m, n = len(heights), len(heights[0])
+        dr, dc = [-1, 1, 0, 0], [0, 0, -1, 1]
+        visited_p, visited_a = set(), set()
+
+        def dfs(r, c, visited):
+            # base condition
+            if (r, c) in visited:  # 방문 여부 확인
+                return
+
+            # 방문 처리
+            visited.add((r, c))
+
+            # recur
+            for i in range(4):
+                nr, nc = r + dr[i], c + dc[i]
+
+                if (
+                        0 <= nr < m and 0 <= nc < n  # valid한 범위 확인
+                        and heights[nr][nc] >= heights[r][c]  # height 값이 현재 칸보다 gte인지 확인 (** 거꾸로 확인하므로)
+                ):
+                    dfs(nr, nc, visited)
+
+        # edges로부터 DFS로 방문
+        for r in range(m):
+            dfs(r, 0, visited_p)
+            dfs(r, n - 1, visited_a)
+        for c in range(n):
+            dfs(0, c, visited_p)
+            dfs(m - 1, c, visited_a)
+
+        # pacific과 atlantic의 교집합 반환
+        return [list(cell) for cell in visited_p & visited_a]
diff --git a/sum-of-two-integers/seungriyou.py b/sum-of-two-integers/seungriyou.py
new file mode 100644
index 000000000..9c3b4a6a0
--- /dev/null
+++ b/sum-of-two-integers/seungriyou.py
@@ -0,0 +1,43 @@
+# https://leetcode.com/problems/sum-of-two-integers/
+
+class Solution:
+    def getSum(self, a: int, b: int) -> int:
+        """
+        [Complexity]
+            - TC: O(1)
+            - SC: O(1)
+
+        [Approach]
+            덧셈 구현 시 주요한 요소는 carry와 value 값이다.
+            예를 들어 이진수 11과 101의 덧셈을 생각해보면, 각 자리에서 발생하는 carry와 value는 다음과 같다.
+                       a =  0   1   1
+                       b =  1   0   1
+                       ---------------
+                value)      1   1   0   (= a ^ b)
+                carry)      0   0   1   (= a & b)
+            이때, 어떤 자리에서 발생한 carry는 한 칸 left shift 되어 다시 덧셈을 수행하듯 적용되어야 함에 주의한다.
+                value)      1   1   0
+                carry)  0   0   1   0   (<<= 1)
+
+            이 과정을 carry가 0이 될 때까지 반복해나간다.
+                value)  0   1   0   0   (= a ^ b)
+                carry)  0   1   0   0   (= (a & b) << 1)
+
+                value)  0   0   0   0   (= a ^ b)
+                carry)  1   0   0   0   (= (a & b) << 1)
+
+                value)  1   0   0   0   (= a ^ b)               -> RESULT
+                carry)  0   0   0   0   (= (a & b) << 1)        -> END
+
+            하지만 파이썬에서는 int를 32bit 보다 큰 메모리에 저장하므로 음수가 들어올 경우에 대비해 다음의 작업을 추가로 수행해야 한다.
+                - 음수가 들어온다면 carry가 32bit를 넘어서도 계속 더해질 것이므로, while 문 조건식에의 carry에 32bit masking을 수행한다.
+                - (b & mask) == 0이지만 b > 0인 경우에는 a의 32bit 범위 밖에 overflow가 존재하는 것이므로, 결과 값에도 32bit masking을 수행한다.
+        """
+
+        mask = 0xffffffff   # 32bit masking
+
+        # carry가 0이 될 떄까지 반복 (음수가 들어오는 경우, 32bit masking 후 확인)
+        while (b & mask) != 0:
+            a, b = a ^ b, (a & b) << 1      # value, carry
+
+        return (a & mask) if b > 0 else a   # 음수 (overflow) 처리