Skip to content

[KwonNayeon] Week 9 #982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions find-minimum-in-rotated-sorted-array/KwonNayeon.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

시간 복잡도 제한에 맞추어 binary search 를 적절하게 사용하신것 같아요!

Original file line number Diff line number Diff line change
@@ -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]
58 changes: 58 additions & 0 deletions linked-list-cycle/KwonNayeon.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비교 가능하도록 두가지 방법 모두 친절한 설명과 함께 올려주셨네요. 두번째 방법이 아무래도 LinkedList 의 특성을 활용한 풀이 방법이라 생각해요 :)

Original file line number Diff line number Diff line change
@@ -0,0 +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:
- Solution 1: O(n)
- Solution 2: O(n)

Space Complexity:
- Solution 1: O(n) - visited set에 모든 노드를 저장할 수 있음
- Solution 2: O(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

37 changes: 37 additions & 0 deletions maximum-product-subarray/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -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


49 changes: 49 additions & 0 deletions minimum-window-substring/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -0,0 +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: O(s * t)
- for 루프로 s의 길이만큼 반복
- while 루프 안의 all() 조건에서 t의 각 문자 비교
- 따라서 O(s * t)

Space Complexity: O(s + t)
- t_counts: O(t)의 공간
- w_counts: O(s)의 공간
- 따라서 O(s + t)

풀이방법:
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 ""

53 changes: 53 additions & 0 deletions pacific-atlantic-water-flow/KwonNayeon.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pac 과 atl 을 각각 배열로 만들어서 true, false를 활용해 둘 다 true인 경우를 반환하는 풀이도 있는데, 해당하는 경우에만 set에 추가하여 풀이하면 공간을 좀 더 효율적으로 사용할 수있겠네요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

훨씬 공간효율적인 풀이네요! 이 방식으로도 한번 풀어보겠습니다 👍

Original file line number Diff line number Diff line change
@@ -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)