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)