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)