diff --git a/binary-tree-maximum-path-sum/alphaorderly.py b/binary-tree-maximum-path-sum/alphaorderly.py new file mode 100644 index 0000000000..e1b4cc6436 --- /dev/null +++ b/binary-tree-maximum-path-sum/alphaorderly.py @@ -0,0 +1,38 @@ +# 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 +""" +시간복잡도: O(n) +공간복잡도: O(n) +""" +class Solution: + def maxPathSum(self, root: Optional[TreeNode]) -> int: + def calc(node: Optional[TreeNode]): + if not node: + # (한쪽 서브트리에서 root를 향해 올라오는 경로의 최대합, + # 해당 서브트리 내 임의 경로의 최대 합) + return (-float("inf"), -float("inf")) + + # 왼쪽 서브트리 결과 + # left: 왼쪽 자식으로부터 root를 향해 이어질 수 있는 단일 경로의 최대 합 + # left_root: 왼쪽 서브트리 전체에서 얻을 수 있는 임의 경로의 최대 합 + left, left_root = calc(node.left) + + # 오른쪽 서브트리 결과 + # right: 오른쪽 자식으로부터 root를 향해 이어질 수 있는 단일 경로의 최대 합 + # right_root: 오른쪽 서브트리 전체에서 얻을 수 있는 임의 경로의 최대 합 + right, right_root = calc(node.right) + + # 한쪽(왼쪽/오른쪽) 또는 아무쪽도 안타거나(0) 현재노드로 연결 가능, 단일 경로 최대 합 + current = max(left, right, 0) + node.val + # 현재 노드를 루트로 하는 서브트리에서 가능한 모든 경로 중 최대 합 (각 자식 0 미만이면 안탐) + current_root = max(max(left, 0) + max(right, 0) + node.val, left_root, right_root) + + return (current, current_root) + + _, ans = calc(root) + + return ans diff --git a/graph-valid-tree/alphaorderly.py b/graph-valid-tree/alphaorderly.py new file mode 100644 index 0000000000..42773a1f7a --- /dev/null +++ b/graph-valid-tree/alphaorderly.py @@ -0,0 +1,49 @@ +""" +시간복잡도: O(n) +공간복잡도: O(n) + +먼저 트리의 조건에 맞도록 간선의 갯수가 노드의 갯수 - 1인지 확인하고 +Union-Find 알고리즘을 사용하여 간선을 하나씩 추가하며 사이클 여부를 확인한다. +""" +class UnionFind: + def __init__(self, n: int): + self.parent = [-1] * n + self.rank = [0] * n + + def find(self, target: int) -> int: + if self.parent[target] == -1: + return target + + self.parent[target] = self.find(self.parent[target]) + return self.parent[target] + + def union(self, a: int, b: int) -> bool: + a = self.find(a) + b = self.find(b) + + if a == b: + return False + + if self.rank[a] < self.rank[b]: + a, b = b, a + + self.parent[b] = a + if self.rank[a] == self.rank[b]: + self.rank[a] += 1 + + return True + + +class Solution: + def validTree(self, n: int, edges: List[List[int]]) -> bool: + + if len(edges) < n - 1: + return False + + u = UnionFind(n) + + for a, b in edges: + if not u.union(a, b): + return False + + return True diff --git a/merge-intervals/alphaorderly.py b/merge-intervals/alphaorderly.py new file mode 100644 index 0000000000..f3c271d2a5 --- /dev/null +++ b/merge-intervals/alphaorderly.py @@ -0,0 +1,32 @@ +""" +시간복잡도: O(n log n) +공간복잡도: O(n) + +1. 인터벌을 시작시간이 이른 순서대로 정렬한다. +2. 첫 번째 인터벌을 시작시간과 종료시간으로 설정한다. +3. 두 번째 인터벌부터 시작시간이 이전 인터벌의 종료시간보다 작거나 같은 경우 종료시간을 최대값으로 업데이트한다. +4. 그렇지 않은 경우 이전 인터벌을 결과에 추가하고 현재 인터벌을 시작시간과 종료시간으로 설정한다. +5. 마지막 인터벌을 결과에 추가한다. +""" +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + intervals.sort() + + N = len(intervals) + schedule = [] + + start, end = intervals[0] + + for i in range(1, N): + event_start, event_end = intervals[i] + + if event_start <= end: + end = max(end, event_end) + else: + schedule.append([start, end]) + start = event_start + end = event_end + + schedule.append([start, end]) + + return schedule diff --git a/missing-number/alphaorderly.py b/missing-number/alphaorderly.py new file mode 100644 index 0000000000..fffd155044 --- /dev/null +++ b/missing-number/alphaorderly.py @@ -0,0 +1,14 @@ +""" +시간복잡도: O(n) +공간복잡도: O(1) + +'target'을 배열의 길이(n)로 설정한 뒤, 0부터 n-1까지의 인덱스와 배열의 모든 값을 xor 연산합니다. +이 과정을 거치면, 배열과 인덱스 모두에 존재하는 값은 xor 연산으로 소거되어 사라집니다(x ^ x = 0). +최종적으로 남는 값이 배열에 존재하지 않는 누락된 숫자가 됩니다. +""" +class Solution: + def missingNumber(self, nums: List[int]) -> int: + target = len(nums) + for i, v in enumerate(nums): + target ^= i ^ v + return target diff --git a/reorder-list/alphaorderly.py b/reorder-list/alphaorderly.py new file mode 100644 index 0000000000..4ac052b75f --- /dev/null +++ b/reorder-list/alphaorderly.py @@ -0,0 +1,28 @@ +""" +시간복잡도: O(n) +공간복잡도: O(1) + +1. 토끼와 거북이 포인터를 이용해 연결 리스트의 중간 지점을 찾는다. +2. 중간 지점부터 끝까지의 리스트를 역순으로 뒤집는다. + - 이 과정에서 앞부분과 뒷부분이 분리된다. +3. 앞부분(head)과 뒤집힌 뒷부분을 교차로 연결하여 순서를 재배열한다. +""" +class Solution: + def reorderList(self, head: Optional[ListNode]) -> None: + """ + Do not return anything, modify head in-place instead. + """ + tortoise = hare = head + + while hare and hare.next: + tortoise = tortoise.next + hare = hare.next.next + + prev, curr = None, tortoise + while curr: + curr.next, prev, curr = prev, curr, curr.next + + a, b = head, prev + while b.next: + a.next, a = b, a.next + b.next, b = a, b.next