Skip to content
Open
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
38 changes: 38 additions & 0 deletions binary-tree-maximum-path-sum/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

binary-tree-maximum-path-sum/alphaorderly.py
# 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
  • 패턴: Binary Search, Tree DP, DFS, Dynamic Programming
  • 설명: 트리의 각 노드에서 왼쪽/오른쪽 부분트리 정보를 조합해 경로의 최대 합을 구하는 방식은 트리 기반 DP(Tree DP)와 DFS를 활용한 패턴입니다. 재귀적으로 하위 정보를 계산하고 이를 합쳐 최댓값을 도출합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(n)

피드백: 각 노드에서 좌우 서브트리의 정보를 조합해 전체 경로 최대치를 갱신하는 방식으로 트리 전체를 한 번 탐색합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -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
49 changes: 49 additions & 0 deletions graph-valid-tree/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

graph-valid-tree/alphaorderly.py
"""
시간복잡도: 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
  • 패턴: Union Find
  • 설명: 주어진 그래프가 트리인지 확인하기 위해 Union-Find로 사이클 여부를 검사하고, 간선 개수가 노드 수의 -1인지 확인하는 방식으로 문제를 풀이한다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(n)

피드백: 초기 간선 개수 확인으로 빠르게 거짓 양성을 걸러내고, 각 간선마다 사이클 여부를 체크합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions merge-intervals/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

merge-intervals/alphaorderly.py
"""
시간복잡도: 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
  • 패턴: Sort, Two Pointers, Greedy
  • 설명: 구현은 간격을 시작점 기준 오름차순으로 정렬한 뒤, 인접 구간을 비교하며 겹치면 끝점을 확장하고, 겹치지 않으면 결과에 추가하는 방식으로 최적 분할을 수행한다. 이 과정에서 선형 탐색과 정렬을 결합한 그리디 패턴으로 해석된다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n log n)
Space O(n)

피드백: 정렬과 단일 순회로 병합을 수행하므로 시간 복잡도는 정렬에 의존합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions missing-number/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

missing-number/alphaorderly.py
"""
시간복잡도: 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
  • 패턴: Bit Manipulation, Two Pointers
  • 설명: XOR 연산으로 인덱스와 값의 차집합을 제거하여 missing number를 찾는 방식은 비트 조작(Bit Manipulation) 패턴에 해당합니다. 문제의 해법은 여러 요소를 동시에 결합해 한 값만 남기는 전형적인 XOR 기반 접근으로 설명됩니다. Two Pointers 패턴은 사용되지 않지만, 배열 순회와 누락 원소 찾기라는 맥락에서 Bit Manipulation이 핵심입니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(1)

피드백: 배열 원소와 인덱스의 XOR을 이용해 누락된 값을 구합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

missing-number/alphaorderly.py
"""
시간복잡도: 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
  • 패턴: Bit Manipulation
  • 설명: 배열 원소와 인덱스의 값을 XOR로 소거하는 방식으로 누락된 숫자를 찾는 비트 연산 패턴입니다. 리스트의 길이를 대상으로 하여 모든 인덱스와 값과의 XOR를 누적하면 남은 값이 정답이 됩니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(1)

피드백: 모든 원소와 인덱스 값을 순회하며 XOR 연산으로 동일한 값은 소거하므로 누락된 값이 최종적으로 남습니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions reorder-list/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🏷️ 알고리즘 패턴 분석

reorder-list/alphaorderly.py
"""
시간복잡도: 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
  • 패턴: Two Pointers, Reorder List
  • 설명: 중간 지점 찾기에 토끼-거북이 포인터로 Two Pointers를 이용하고, 뒤쪽 부분을 역순으로 뒤집어 앞부분과 교차 연결하는 과정으로 리스트를 재배열하는 패턴이 보입니다. 전체 흐름은 연결 리스트를 이용한 순차적 조작과 부분집합 재구성으로 구성됩니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(1)

피드백: 두 번의 선형 순회를 통해 in-place 재배열을 달성합니다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

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