diff --git a/graph-valid-tree/pmjuu.py b/graph-valid-tree/pmjuu.py new file mode 100644 index 000000000..13f6d76fe --- /dev/null +++ b/graph-valid-tree/pmjuu.py @@ -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 diff --git a/non-overlapping-intervals/pmjuu.py b/non-overlapping-intervals/pmjuu.py new file mode 100644 index 000000000..5d2b969c1 --- /dev/null +++ b/non-overlapping-intervals/pmjuu.py @@ -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 diff --git a/number-of-connected-components-in-an-undirected-graph/pmjuu.py b/number-of-connected-components-in-an-undirected-graph/pmjuu.py new file mode 100644 index 000000000..a7607e6e5 --- /dev/null +++ b/number-of-connected-components-in-an-undirected-graph/pmjuu.py @@ -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() diff --git a/remove-nth-node-from-end-of-list/pmjuu.py b/remove-nth-node-from-end-of-list/pmjuu.py new file mode 100644 index 000000000..01cc33638 --- /dev/null +++ b/remove-nth-node-from-end-of-list/pmjuu.py @@ -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 diff --git a/same-tree/pmjuu.py b/same-tree/pmjuu.py new file mode 100644 index 000000000..37f183773 --- /dev/null +++ b/same-tree/pmjuu.py @@ -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)