From a32067179b6e38e1d8ce5734b9af630e4c5a64a7 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Sun, 2 Feb 2025 09:45:45 +0900 Subject: [PATCH 1/6] chore: add placeholder for "Linked List Cycle" --- linked-list-cycle/KwonNayeon.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 linked-list-cycle/KwonNayeon.py diff --git a/linked-list-cycle/KwonNayeon.py b/linked-list-cycle/KwonNayeon.py new file mode 100644 index 000000000..75ef8d540 --- /dev/null +++ b/linked-list-cycle/KwonNayeon.py @@ -0,0 +1,13 @@ +""" +Constraints: +- + +Time Complexity: +- + +Space Complexity: +- + +풀이방법: +1. +""" From 85687e8c110087da2c6ea3d3710af8228815bd42 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Mon, 3 Feb 2025 15:01:48 +0900 Subject: [PATCH 2/6] solve: Linked List Cycle --- linked-list-cycle/KwonNayeon.py | 57 +++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/linked-list-cycle/KwonNayeon.py b/linked-list-cycle/KwonNayeon.py index 75ef8d540..13fa2d99d 100644 --- a/linked-list-cycle/KwonNayeon.py +++ b/linked-list-cycle/KwonNayeon.py @@ -1,13 +1,58 @@ """ Constraints: -- +- The number of the nodes in the list is in the range [0, 10^4] +- -10^5 <= Node.val <= 10^5 +- pos is -1 or a valid index in the linked-list -Time Complexity: -- +Time Complexity: +- Solution 1: O(n) +- Solution 2: O(n) -Space Complexity: -- +Space Complexity: +- Solution 1: O(n) - visited set에 모든 노드를 저장할 수 있음 +- Solution 2: O(1) - 추가 메모리 사용하지 않음 풀이방법: -1. +1. 처음엔 직관적인 방법으로 해결, 한 번 마주친 노드를 다시 만나는지를 체크하는 방식 +2. slow, fast 두 개의 노드를 활용, 만약 cycle이 존재하는 경우 fast가 slow와 언젠가 만나게 됨, + 만약 cycle이 없다면 둘은 만나지 않음 """ + +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +# Solution 1: 한 번 마주친 노드를 다시 만나는지를 체크 +class Solution: + def hasCycle(self, head: Optional[ListNode]) -> bool: + visited = set() + + current = head + while current: + if current in visited: + return True + visited.add(current) + current = current.next + + return False + +# Solution 2: 두 개의 포인터 이용 +class Solution: + def hasCycle(self, head: Optional[ListNode]) -> bool: + if not head: + 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 + From 034a387396dd4392fa87f9b4168a90a3c8da22fe Mon Sep 17 00:00:00 2001 From: Nayeon Date: Tue, 4 Feb 2025 11:39:22 +0900 Subject: [PATCH 3/6] solve: Find Minimum in Rotated Sorted Array --- .../KwonNayeon.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 find-minimum-in-rotated-sorted-array/KwonNayeon.py diff --git a/find-minimum-in-rotated-sorted-array/KwonNayeon.py b/find-minimum-in-rotated-sorted-array/KwonNayeon.py new file mode 100644 index 000000000..bef237e1b --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/KwonNayeon.py @@ -0,0 +1,42 @@ +""" +Constraints: +- n == nums.length +- 1 <= n <= 5000 +- -5000 <= nums[i] <= 5000 +- All the integers of nums are unique. +- nums is sorted and rotated between 1 and n times. + +Time Complexity: O(log n) +- 이진 탐색을 사용하므로 매 단계마다 탐색 범위가 절반으로 줄어듦 + +Space Complexity: O(1) +- 추가 공간을 사용하지 않고 포인터만 사용 + +풀이방법: +1. 이진 탐색(Binary Search) 활용 +2. mid와 right 값을 비교하여 조건을 나눔 + - Case 1: nums[mid] > nums[right] + - 오른쪽 부분이 정렬되어 있지 않음 + - 최솟값은 mid 오른쪽에 존재 + - left = mid + 1 + - Case 2: nums[mid] <= nums[right] + - mid부터 right까지는 정렬되어 있음 + - 최솟값은 mid를 포함한 왼쪽에 존재 가능 + - right = mid +""" + +class Solution: + def findMin(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] From 6d45f22960ad3e1e7ba34106f12e2039bf1fcc88 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Wed, 5 Feb 2025 12:59:12 +0900 Subject: [PATCH 4/6] solve: Pacific Atlantic Water Flow --- pacific-atlantic-water-flow/KwonNayeon.py | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 pacific-atlantic-water-flow/KwonNayeon.py diff --git a/pacific-atlantic-water-flow/KwonNayeon.py b/pacific-atlantic-water-flow/KwonNayeon.py new file mode 100644 index 000000000..7e6e355d2 --- /dev/null +++ b/pacific-atlantic-water-flow/KwonNayeon.py @@ -0,0 +1,53 @@ +""" +Constraints: +- m == heights.length +- n == heights[r].length +- 1 <= m, n <= 200 +- 0 <= heights[r][c] <= 10^5 + +Time Complexity: O(m*n) +- 각 셀을 최대 한 번씩만 방문함 + +Space Complexity: O(m*n) +- visited sets(pacific, atlantic)가 최대 m*n 크기 +- 재귀 호출 스택도 최대 m*n 깊이 가능 + +풀이방법: +1. Pacific(좌측상단)과 Atlantic(우측하단)의 경계에서 시작함 +2. DFS로 현재 높이보다 높거나 같은 인접 셀로만 이동함 (물은 위 -> 아래로 흐르지만, 거꾸로 접근했으니까) +3. 각 바다에서 도달 가능한 셀들을 Set에 저장 +4. 두 Set의 교집합이 정답 (양쪽 바다로 모두 흐를 수 있는 지점들) +""" +class Solution: + def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]: + if not heights: + return [] + + rows, cols = len(heights), len(heights[0]) + pacific = set() + atlantic = set() + + def dfs(r, c, visited): + visited.add((r, c)) + directions = [(1,0), (-1,0), (0,1), (0,-1)] + + for dr, dc in directions: + new_r, new_c = r + dr, c + dc + if (new_r < 0 or new_r >= rows or + new_c < 0 or new_c >= cols or + (new_r, new_c) in visited): + continue + if heights[new_r][new_c] >= heights[r][c]: + dfs(new_r, new_c, visited) + + for c in range(cols): + dfs(0, c, pacific) + for r in range(rows): + dfs(r, 0, pacific) + + for c in range(cols): + dfs(rows-1, c, atlantic) + for r in range(rows): + dfs(r, cols-1, atlantic) + + return list(pacific & atlantic) From 08e7b1dd7b6e53e19ba443638f7e2405dcfbcf2c Mon Sep 17 00:00:00 2001 From: Nayeon Date: Thu, 6 Feb 2025 15:14:46 +0900 Subject: [PATCH 5/6] solve: Maximum Product Subarray --- maximum-product-subarray/KwonNayeon.py | 37 ++++++++++++++++++++++++++ minimum-window-substring/KwonNayeon.py | 14 ++++++++++ 2 files changed, 51 insertions(+) create mode 100644 maximum-product-subarray/KwonNayeon.py create mode 100644 minimum-window-substring/KwonNayeon.py diff --git a/maximum-product-subarray/KwonNayeon.py b/maximum-product-subarray/KwonNayeon.py new file mode 100644 index 000000000..ddef49b53 --- /dev/null +++ b/maximum-product-subarray/KwonNayeon.py @@ -0,0 +1,37 @@ +""" +Constraints: +- 1 <= nums.length <= 2 * 10^4 +- -10 <= nums[i] <= 10 +- The product of any subarray of nums is guaranteed to fit in a 32-bit integer. + +Time Complexity: +- O(n): 배열을 한 번만 순회하면서 각 위치에서 상수 시간 연산만 수행 + +Space Complexity: +- O(1): 고정된 추가 변수만 사용 (curr_max, curr_min, ...) + +풀이방법: +1. DP로 각 위치에서 가능한 최대곱과 최소곱을 동시에 추적함 +2. 각 위치에서 세 개의 선택지 존재: 새로 시작 vs 이전 최대곱과 곱하기 vs 이전 최소곱과 곱하기 +3. 최소곱이 필요한 이유: 나중에 음수를 만났을 때 최대값이 될 수 있기 때문 +4. 매 단계마다 result 업데이트 + +고려사항: +1. 값이 0인 경우 → 새로 시작해야 함 +2. temp 변수: curr_max를 업데이트하면 curr_min 계산 시 원래 값이 필요함 +""" +class Solution: + def maxProduct(self, nums: List[int]) -> int: + curr_max = nums[0] + curr_min = nums[0] + result = nums[0] + + for i in range(1, len(nums)): + temp = curr_max + curr_max = max(nums[i], curr_max * nums[i], curr_min * nums[i]) + curr_min = min(nums[i], temp * nums[i], curr_min * nums[i]) + result = max(result, curr_max) + + return result + + diff --git a/minimum-window-substring/KwonNayeon.py b/minimum-window-substring/KwonNayeon.py new file mode 100644 index 000000000..0efe091c3 --- /dev/null +++ b/minimum-window-substring/KwonNayeon.py @@ -0,0 +1,14 @@ +""" +Constraints: +- + +Time Complexity: +- + +Space Complexity: +- + +풀이방법: +1. +""" + From 5140ffdada43abcd98413cdb2cb21a44f0b95329 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Sat, 8 Feb 2025 05:29:43 +0900 Subject: [PATCH 6/6] solve: Minimum Window Substring --- minimum-window-substring/KwonNayeon.py | 47 ++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/minimum-window-substring/KwonNayeon.py b/minimum-window-substring/KwonNayeon.py index 0efe091c3..b6730723a 100644 --- a/minimum-window-substring/KwonNayeon.py +++ b/minimum-window-substring/KwonNayeon.py @@ -1,14 +1,49 @@ """ Constraints: -- +- m == s.length +- n == t.length +- 1 <= m, n <= 10^5 +- s and t consist of uppercase and lowercase English letters. -Time Complexity: -- +Time Complexity: O(s * t) +- for 루프로 s의 길이만큼 반복 +- while 루프 안의 all() 조건에서 t의 각 문자 비교 +- 따라서 O(s * t) -Space Complexity: -- +Space Complexity: O(s + t) +- t_counts: O(t)의 공간 +- w_counts: O(s)의 공간 +- 따라서 O(s + t) 풀이방법: -1. +1. Counter로 t의 문자 빈도수 저장 +2. 슬라이딩 윈도우로 s 탐색: + - high 포인터로 윈도우를 확장하며 필요한 문자 찾기 + - 필요한 문자를 모두 찾으면 low 포인터로 윈도우 축소 +3. 최소 길이의 윈도우 반환 + +메모: +- 풀이 방법을 보고 익힘 +- 해시맵과 슬라이딩 윈도우 관련 다른 문제들을 풀고 이 문제 스스로 풀어보기 """ +class Solution: + def minWindow(self, s: str, t: str) -> str: + + t_counts = Counter(t) + w_counts = Counter() + + min_low, min_high = 0, len(s) + low = 0 + + for high in range(len(s)): + w_counts[s[high]] += 1 + + while all(t_counts[ch] <= w_counts[ch] for ch in t_counts): + if high - low < min_high - min_low: + min_low, min_high = low, high + if s[low] in t_counts: + w_counts[s[low]] -= 1 + low += 1 + + return s[min_low : min_high + 1] if min_high < len(s) else ""