Skip to content

[Lyla] Week 12 #1058

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 5 commits into from
Mar 1, 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
45 changes: 45 additions & 0 deletions graph-valid-tree/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'''
노드의 개수를 n, 간선의 개수를 e 라고 할때,

시간 복잡도: O(n + e)
- 그래프의 모든 노드와 간선을 방문하므로 O(n + e)

공간 복잡도: O(n + e)
- 인접 리스트와 방문 배열을 저장하는 데 O(n + e)의 공간이 필요합니다.
'''
from typing import List

class Solution:
def validTree(self, n: int, edges: List[List[int]]) -> bool:
graph = { i: [] for i in range(n) }
for u, v in edges:
graph[u].append(v)
graph[v].append(u)

visited = set()

def hasCycle(node, parent):
if node in visited:
return True

visited.add(node)

for neighbor in graph[node]:
if neighbor == parent:
continue # 부모 노드로 돌아가지 않기
if hasCycle(neighbor, node):
return True

return False

# 0번 노드에서 DFS 시작
if hasCycle(0, -1):
return False

# 모든 노드가 방문되었는지 확인 (연결성 체크)
return len(visited) == n

# Example
solution = Solution()
print(solution.validTree(5, [[0, 1], [0, 2], [0, 3], [1, 4]])) # Output: True
print(solution.validTree(5, [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]])) # Output: False
22 changes: 22 additions & 0 deletions non-overlapping-intervals/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'''
시간 복잡도: O(n log n)
공간 복잡도: O(1)
'''
from typing import List


class Solution:
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
intervals.sort()
count = 0
iter_intervals = iter(intervals)
prev_end = next(iter_intervals)[1]

for start, end in iter_intervals:
if prev_end > start:
count += 1
prev_end = min(prev_end, end)
else:
prev_end = end

return count
50 changes: 50 additions & 0 deletions number-of-connected-components-in-an-undirected-graph/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'''
n: 노드 개수 / e: 간선 개수
시간 복잡도: O(n + e)
공간 복잡도: O(n + e)
'''
from typing import List

class Solution:
def count_components(self, n: int, edges: List[List[int]]) -> int:
graph = {i: [] for i in range(n)}
for u, v in edges:
graph[u].append(v)
graph[v].append(u)

visited = set()
def dfs(node):
visited.add(node)

for neighbor in graph[node]:
if neighbor not in visited:
dfs(neighbor)

count = 0
for node in graph:
if node not in visited:
count += 1
dfs(node)

return count

# Test function
def test():
solution = Solution()
test_cases = [
(3, [[0, 1], [0, 2]], 1),
(6, [[0, 1], [1, 2], [2, 3], [4, 5]], 2),
(4, [[0, 1], [2, 3]], 2),
(1, [], 1),
(4, [[0, 1], [2, 3], [1, 2]], 1)
]

for i, (n, edges, expected) in enumerate(test_cases):
result = solution.count_components(n, edges)
print(f"Test case {i+1}: Input: n={n}, edges={edges} -> Output: {result}, Expected: {expected}")
if result != expected:
print(f"# Test case {i+1} failed: expected {expected}, got {result}")
print("\n")

# Run tests
test()
60 changes: 60 additions & 0 deletions remove-nth-node-from-end-of-list/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'''
시간 복잡도: O(n)
공간 복잡도: O(1)
'''
from typing import Optional

# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next

# 리스트 총 길이 계산
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
# 리스트 길이 계산
length = 1
current = head
while current.next:
length += 1
current = current.next

# 제거할 노드가 첫 번째(head)인 경우
if n == length:
return head.next

index = 0
current = head

# 제거 대상 노드 전까지 이동
for _ in range(length - n - 1):
current = current.next

# 제거 대상 노드 건너뛰기
current.next = current.next.next

return head

# Two-Pointer
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
first = second = head

# 1. `first`를 n 만큼 이동 → `second`와의 간격 유지
for _ in range(n):
first = first.next

# 제거 대상이 첫번째 노드인 경우, next 반환
if not first:
return head.next

# 2. `first`가 끝까지 갈 때까지 `second`도 함께 이동
while first.next:
first = first.next
second = second.next

# 3. `second.next`가 가리키는 노드 제거
second.next = second.next.next

return head
21 changes: 21 additions & 0 deletions same-tree/pmjuu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'''
시간 복잡도: O(n)
공간 복잡도: O(n)
'''
from typing import Optional

# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right

class Solution:
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
if not p and not q:
return True
if not p or not q:
return False

return p.val == q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)