diff --git a/find-minimum-in-rotated-sorted-array/dusunax.py b/find-minimum-in-rotated-sorted-array/dusunax.py
new file mode 100644
index 000000000..80241dbc2
--- /dev/null
+++ b/find-minimum-in-rotated-sorted-array/dusunax.py
@@ -0,0 +1,41 @@
+'''
+# 153. Find Minimum in Rotated Sorted Array
+
+> **why binary search works in a "rotated" sorted array?**  
+> rotated sorted array consists of **two sorted subarrays**, and the minimum value is the second sorted subarray's first element.  
+> so πŸ‘‰ find the point that second sorted subarray starts.   
+>
+> - if nums[mid] > nums[right]? => the pivot point is in the right half.  
+> - if nums[mid] <= nums[right]? => the pivot point is in the left half.  
+> - loop until left and right are the same.
+'''
+class Solution:
+    '''
+    ## A. brute force(not a solution)
+    - TC: O(n)
+    - SC: O(1)
+    '''
+    def findMinBF(self, nums: List[int]) -> int:
+        if len(nums) == 1:
+            return nums[0]
+
+        return min(nums) # check all elements
+
+    '''
+    ## B. binary search
+    - TC: O(log n)
+    - SC: O(1)
+    '''
+    def findMinBS(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]
diff --git a/linked-list-cycle/dusunax.py b/linked-list-cycle/dusunax.py
new file mode 100644
index 000000000..333647c84
--- /dev/null
+++ b/linked-list-cycle/dusunax.py
@@ -0,0 +1,33 @@
+'''
+# 141. Linked List Cycle
+
+use two pointers, Floyd's Tortoise and Hare algorithm
+
+> Tortoise and Hare algorithm  
+>- slow pointer moves one step at a time
+>- fast pointer moves two steps at a time
+>- if there is a cycle, slow and fast will meet at some point
+>- if there is no cycle, fast will reach the end of the list
+
+## Time Complexity: O(n)
+In the worst case, we need to traverse the entire list to determine if there is a cycle.
+
+## Space Complexity: O(1)
+no extra space is used, only the two pointers.
+'''
+class Solution:
+    def hasCycle(self, head: Optional[ListNode]) -> bool:
+        if not head or not head.next:
+            return False
+        
+        slow = head
+        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/dusunax.py b/maximum-product-subarray/dusunax.py
new file mode 100644
index 000000000..e2f796ce8
--- /dev/null
+++ b/maximum-product-subarray/dusunax.py
@@ -0,0 +1,31 @@
+'''
+# 152. Maximum Product Subarray
+
+solution reference: https://www.algodale.com/problems/maximum-product-subarray/
+
+## μ΅œλŒ€ κ³± λ°°μ—΄ κ΅¬ν•˜κΈ°
+- 연속 λ°°μ—΄(subarray)에 μ–‘μˆ˜, 음수, 0이 포함될 수 μžˆλ‹€.
+- μŒμˆ˜κ°€ 결과에 영ν–₯을 λ―ΈμΉ  수 있기 λ•Œλ¬Έμ— μ΅œμ†Œκ°’/μ΅œλŒ€κ°’ 좔적이 ν•„μš”ν•˜λ‹€.
+
+## κ°’
+- result: μ΅œμ’…μ μœΌλ‘œ λ°˜ν™˜ν•  κ°’
+- min_prod: ν˜„μž¬κΉŒμ§€μ˜ μ΅œμ†Œ κ³± κ°’ (음수λ₯Ό κ³ λ €ν•œ 좔적)
+- max_prod: ν˜„μž¬κΉŒμ§€μ˜ μ΅œλŒ€ κ³± κ°’
+
+## μƒˆλ‘œμš΄ κ°’ num이 μ£Όμ–΄μ‘Œμ„ λ•Œ
+- μƒˆλ‘œμš΄ 배열을 μ‹œμž‘ν•  μ§€, κΈ°μ‘΄ 배열에 μΆ”κ°€ν•  μ§€ κ²°μ •
+- ν›„λ³΄λ“€λ‘œ μ΅œλŒ€κ°’μ˜ κ°€λŠ₯성을 ν™•μΈν•˜κ³  resultλ₯Ό μ—…λ°μ΄νŠΈν•œλ‹€.
+'''
+class Solution:
+    def maxProduct(self, nums: List[int]) -> int:
+        result = nums[0]
+        min_prod = 1
+        max_prod = 1
+
+        for num in nums:
+            candidates = (min_prod * num, max_prod * num, num)
+            min_prod = min(candidates)
+            max_prod = max(candidates)
+            result = max(max_prod, result)
+
+        return result
diff --git a/minimum-window-substring/dusunax.py b/minimum-window-substring/dusunax.py
new file mode 100644
index 000000000..b8d6fe66c
--- /dev/null
+++ b/minimum-window-substring/dusunax.py
@@ -0,0 +1,68 @@
+'''
+# 76. Minimum Window Substring 
+
+solution reference: https://www.algodale.com/problems/minimum-window-substring/
+
+## μ£Όμ–΄μ§„ λ¬Έμžμ—΄ sμ—μ„œ λ¬Έμžμ—΄ t의 λͺ¨λ“  문자λ₯Ό ν¬ν•¨ν•˜λŠ” μ΅œμ†Œ μœˆλ„μš°λ₯Ό μ°Ύμ•„ λ°˜ν™˜ν•˜κΈ° πŸ”₯
+
+> μŠ¬λΌμ΄λ”© μœˆλ„μš°, μ΅œμ†Œ μœˆλ„μš° μ°ΎκΈ°, λ¬Έμžμ—΄μ˜ λΉˆλ„ 좔적, t의 λͺ¨λ“  λ¬Έμžκ°€ ν˜„μž¬ μœˆλ„μš°μ— ν¬ν•¨λ˜μ–΄ μžˆλŠ”μ§€ 좔적
+
+- μœˆλ„μš°μ˜ 였λ₯Έμͺ½ 끝을 ν™•μž₯ν•˜λ©΄μ„œ, ν•„μš”ν•œ λͺ¨λ“  λ¬Έμžκ°€ ν¬ν•¨λ˜μ—ˆμ„ λ•Œ, μœˆλ„μš°μ˜ 크기λ₯Ό μ΅œμ†Œν™”ν•˜κΈ°
+
+## κ°’
+- counts: ν•„μš”ν•œ λ¬Έμžκ°€ λͺ‡ 번 λ“±μž₯ν•˜λŠ”μ§€ 좔적
+- n_included: μœˆλ„μš° μ•ˆμ—μ„œ t에 ν•„μš”ν•œ 문자 개수 좔적
+- low, high: μŠ¬λΌμ΄λ”© μœˆλ„μš°μ˜ μ–‘ 끝
+- min_low max_high: λ°˜ν™˜κ°’, μŠ¬λΌμ΄λ”© μœˆλ„μš°μ˜ μ–‘ 끝
+
+## s 탐색
+- s의 였λ₯Έμͺ½ 끝을 νƒμƒ‰ν•©λ‹ˆλ‹€.
+  - ν˜„μž¬ λ¬Έμžκ°€ t에 μ‘΄μž¬ν•œλ‹€λ©΄(counts에 ν‚€κ°€ 쑴재)
+    - 그리고 ν•„μš”ν•œ 문자라면(값이 1 이상)
+        - μœˆλ„μš° λ‚΄λΆ€μ˜ ν•„μš” 문자 개수λ₯Ό ν•˜λ‚˜ μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.
+    - ν•΄λ‹Ή 문자의 λ“±μž₯ countλ₯Ό ν•˜λ‚˜ κ°μ†Œμ‹œν‚΅λ‹ˆλ‹€.
+
+## μœˆλ„μš° μΆ•μ†Œν•˜κΈ°
+- μ•„λž˜ 문항을 ν•„μš”ν•œ 값이 μœˆλ„μš° μ•ˆμ— μ‘΄μž¬ν•˜λŠ” λ™μ•ˆ λ°˜λ³΅ν•©λ‹ˆλ‹€.
+1. ν˜„μž¬ κ΅¬ν•œ μœˆλ„μš°κ°€ 더 μž‘μ€ μ§€ ν™•μΈν•˜κ³ , μž‘λ‹€λ©΄ λ°˜ν™˜ν•  μœˆλ„μš°λ₯Ό μ—…λ°μ΄νŠΈ ν•©λ‹ˆλ‹€.
+2. s의 μ™Όμͺ½ 끝을 νƒμƒ‰ν•©λ‹ˆλ‹€.
+  - ν˜„μž¬ λ¬Έμžκ°€ t에 μ‘΄μž¬ν•œλ‹€λ©΄(counts에 ν‚€κ°€ 쑴재)
+    - ν•΄λ‹Ή 문자의 λ“±μž₯ countλ₯Ό ν•˜λ‚˜ μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.
+    - 그리고 ν•„μš”ν•œ 문자라면(값이 1 이상)
+        - μœˆλ„μš° λ‚΄λΆ€μ˜ ν•„μš” 문자 개수λ₯Ό ν•˜λ‚˜ μΆ•μ†Œμ‹œν‚΅λ‹ˆλ‹€.(반볡문의 쑰건을 λ²—μ–΄λ‚©λ‹ˆλ‹€.)
+3. λ‹€μŒ 탐색 μ „ μ™Όμͺ½ μœ„μΉ˜λ₯Ό ν•˜λ‚˜ μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.
+
+## λ°˜ν™˜
+- μ΅œμ†Œ μœˆλ„μš°μ˜ μ‹œμž‘κ³Ό 끝을 low와 high + 1둜 λ°˜ν™˜ν•˜λ˜, μœ νš¨ν•œ μœˆλ„μš°κ°€ μ•„λ‹ˆλΌλ©΄ ""을 λ°˜ν™˜ν•©λ‹ˆλ‹€.
+'''
+class Solution:
+    def minWindow(self, s: str, t: str) -> str:
+        min_low = 0
+        max_high = len(s)
+        counts = Counter(t)
+        n_included = 0
+
+        low = 0
+        # s 탐색
+        for high in range(len(s)):
+            char_high = s[high]
+            if char_high in counts: 
+                if counts[char_high] > 0:
+                    n_included += 1
+                counts[char_high] -= 1
+
+            # μœˆλ„μš° μΆ•μ†Œν•˜κΈ°
+            while n_included == len(t):
+                if high - low < max_high - min_low: # 1
+                    min_low = low
+                    max_high = high
+                    
+                char_low = s[low] 
+                if char_low in counts: # 2
+                    counts[char_low] += 1
+                    if counts[char_low] > 0:
+                        n_included -= 1
+
+                low += 1 # 3
+            
+        return s[min_low: max_high + 1] if max_high < len(s) else "" 
diff --git a/pacific-atlantic-water-flow/dusunax.py b/pacific-atlantic-water-flow/dusunax.py
new file mode 100644
index 000000000..7588a41cd
--- /dev/null
+++ b/pacific-atlantic-water-flow/dusunax.py
@@ -0,0 +1,42 @@
+'''
+# 417. Pacific Atlantic Water Flow
+
+## Time Complexity: O(n * m)
+- dfs is called for each cell in the grid, and each cell is visited once.
+
+## Space Complexity: O(n * m)
+- pacific and atlantic sets store the cells that can flow to the pacific and atlantic oceans respectively.
+'''
+class Solution:
+    def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
+        if len(heights) == 1 and len(heights[0]) == 1:
+            return [[0, 0]]
+        
+        max_row, max_col = len(heights), len(heights[0])
+        pacific, atlantic = set(), set()
+        directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
+
+        def dfs(r, c, visited, prev_height):
+            out_of_bound = r < 0 or c < 0 or r >= max_row or c >= max_col
+            if out_of_bound:
+                return
+
+            current = heights[r][c]
+            is_visited = (r, c) in visited
+            is_uphill = current < prev_height
+            if is_visited or is_uphill:
+                return
+            
+            visited.add((r, c))
+
+            for dr, dc in directions:
+                dfs(r + dr, c + dc, visited, current)
+
+        for r in range(max_row):
+            dfs(r, 0, pacific, heights[r][0]) # left
+            dfs(r, max_col - 1, atlantic, heights[r][max_col - 1]) # right
+        for c in range(max_col):
+            dfs(0, c, pacific, heights[0][c]) # top
+            dfs(max_row - 1, c, atlantic, heights[max_row - 1][c]) # bottom
+
+        return list(pacific & atlantic)