Skip to content

Commit 9fbd3df

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 68f3621 + 3887c3b commit 9fbd3df

File tree

20 files changed

+892
-0
lines changed

20 files changed

+892
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Definition for a binary tree node.
2+
# class TreeNode:
3+
# def __init__(self, val=0, left=None, right=None):
4+
# self.val = val
5+
# self.left = left
6+
# self.right = right
7+
8+
"""
9+
Solution: DFS
10+
1) dfs 로 left, right 각각의 max 값을 구한다.
11+
2) maxSum 을 업데이트하고,
12+
3) return value 로는 leftMax 또는 rightMax 와의 합만 리턴한다.
13+
(left, right 를 둘 다 포함하는 경우와 둘 중 하나만 선택하는 경우를 나눔)
14+
15+
Time: O(n)
16+
Space: O(n)
17+
18+
"""
19+
20+
21+
class Solution:
22+
def maxPathSum(self, root: Optional[TreeNode]) -> int:
23+
maxSum = root.val
24+
25+
def dfs(root):
26+
nonlocal maxSum
27+
if not root:
28+
return 0
29+
30+
leftMax = dfs(root.left)
31+
rightMax = dfs(root.right)
32+
leftMax = max(leftMax, 0)
33+
rightMax = max(rightMax, 0)
34+
35+
maxSum = max(maxSum, root.val + leftMax + rightMax)
36+
return root.val + max(leftMax, rightMax)
37+
38+
dfs(root)
39+
return maxSum
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Time complexity: O(n)
2+
// Space complexity: O(n)
3+
4+
/**
5+
* Definition for a binary tree node.
6+
* function TreeNode(val, left, right) {
7+
* this.val = (val===undefined ? 0 : val)
8+
* this.left = (left===undefined ? null : left)
9+
* this.right = (right===undefined ? null : right)
10+
* }
11+
*/
12+
/**
13+
* @param {TreeNode} root
14+
* @return {number}
15+
*/
16+
var maxPathSum = function (root) {
17+
let answer = Number.MIN_SAFE_INTEGER;
18+
19+
const dfs = (current) => {
20+
const candidates = [current.val];
21+
22+
if (current.left) {
23+
dfs(current.left);
24+
candidates.push(current.left.val + current.val);
25+
}
26+
27+
if (current.right) {
28+
dfs(current.right);
29+
candidates.push(current.right.val + current.val);
30+
}
31+
32+
// 현재 노드가 루트일 경우
33+
if (current.left && current.right) {
34+
answer = Math.max(
35+
answer,
36+
current.left.val + current.right.val + current.val
37+
);
38+
}
39+
40+
current.val = Math.max(...candidates);
41+
answer = Math.max(answer, current.val);
42+
};
43+
44+
dfs(root);
45+
46+
return answer;
47+
};

graph-valid-tree/Chaedie.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""
2+
Conditions of Valid Tree
3+
1) no Loop
4+
2) all nodes has to be connected
5+
6+
Time: O(node + edge)
7+
Space: O(node + edge)
8+
"""
9+
10+
11+
class Solution:
12+
def validTree(self, n: int, edges: List[List[int]]) -> bool:
13+
if not n:
14+
return True
15+
if len(edges) != n - 1:
16+
return False
17+
18+
# Make Graph
19+
graph = {i: [] for i in range(n)}
20+
for n1, n2 in edges:
21+
graph[n1].append(n2)
22+
graph[n2].append(n1)
23+
24+
# loop check
25+
visit = set()
26+
27+
def dfs(i, prev):
28+
if i in visit:
29+
return False
30+
31+
visit.add(i)
32+
for j in graph[i]:
33+
if j == prev:
34+
continue
35+
if not dfs(j, i):
36+
return False
37+
return True
38+
39+
return dfs(0, None) and n == len(visit)

graph-valid-tree/KwonNayeon.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
Valid Tree의 조건:
3+
1. 모든 노드가 연결되어 있어야 함
4+
2. 사이클이 없어야 함
5+
3. edge의 개수는 n-1개
6+
7+
Time Complexity: O(V + E)
8+
- V: 노드의 개수
9+
- E: edge의 개수
10+
11+
Space Complexity: O(V)
12+
- 노드 방문 여부를 저장하는 visited set 사용
13+
14+
풀이방법:
15+
1. 기본 조건 체크: edge의 개수는 n-1개
16+
2. 각 노드별로 연결된 노드들의 정보를 저장
17+
- 무방향 그래프이므로 양쪽 모두 저장
18+
3. DFS로 노드 탐색
19+
- 0번 노드부터 시작해서 연결된 모든 노드를 방문
20+
- 이미 방문한 노드는 재방문하지 않음
21+
4. 모든 노드 방문 확인
22+
- visited의 크기가 n과 같다면 모든 노드가 연결된 것 -> valid tree
23+
"""
24+
def validTree(n, edges):
25+
if len(edges) != n - 1:
26+
return False
27+
28+
adj = [[] for _ in range(n)]
29+
for a, b in edges:
30+
adj[a].append(b)
31+
adj[b].append(a)
32+
33+
visited = set()
34+
35+
def dfs(node):
36+
if node in visited:
37+
return
38+
39+
visited.add(node)
40+
41+
for next_node in adj[node]:
42+
dfs(next_node)
43+
44+
dfs(0)
45+
return len(visited) == n
46+

graph-valid-tree/dusunax.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'''
2+
# 261. Graph Valid Tree
3+
4+
## What constitutes a 🌲
5+
1. it's a graph.
6+
2. Connected: edges == n - 1, visited node count == n
7+
3. Acyclic: there is no cycle.
8+
9+
## Approach A. DFS
10+
use DFS to check if there is a cycle in the graph.
11+
- if there were no cycle & visited node count == n, return True.
12+
13+
## Approach B. Disjoint Set Union (서로소 집합)
14+
use Disjoint Set Union to check if there is a cycle in the graph.
15+
- if you find a cycle, return False immediately.
16+
- if you find no cycle, return True.
17+
18+
### Union Find Operation
19+
- Find: find the root of a node.
20+
- if the root of two nodes is already the same, there is a cycle.
21+
- Union: connect two nodes.
22+
23+
## Approach Comparison
24+
- **A. DFS**: simple and easy to understand.
25+
- **B. Disjoint Set Union**: quicker to check if there is a cycle. if there were more edges, Union Find would be faster.
26+
'''
27+
class Solution:
28+
def validTreeDFS(self, n: int, edges: List[List[int]]) -> bool:
29+
if len(edges) != n - 1:
30+
return False
31+
32+
graph = [[] for _ in range(n)]
33+
for node, neighbor in edges:
34+
graph[node].append(neighbor)
35+
graph[neighbor].append(node)
36+
37+
visited = set()
38+
def dfs(node):
39+
visited.add(node)
40+
for neighbor in graph[node]:
41+
if neighbor not in visited:
42+
dfs(neighbor)
43+
44+
dfs(0)
45+
return len(visited) == n
46+
47+
def validTreeUnionFind(self, n: int, edges: List[List[int]]) -> bool:
48+
if len(edges) != n - 1:
49+
return False
50+
51+
parent = [i for i in range(n)]
52+
53+
def find(x):
54+
if x == parent[x]:
55+
return x
56+
parent[x] = find(parent[x])
57+
return parent[x]
58+
59+
def union(x, y):
60+
parent[find(x)] = find(y)
61+
62+
for node, neighbor in edges:
63+
if find(node) == find(neighbor):
64+
return False
65+
union(node, neighbor)
66+
67+
return True

graph-valid-tree/mike2ox.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Source: https://www.lintcode.com/problem/178/
3+
* Solution: 유효한 트리인지 순회하면서 확인하면 되기에 BFS로 구현
4+
* 시간 복잡도: O(V + E) - 노드와 간선에 한번은 방문
5+
* 공간 복잡도: O(V + E) - 인접리스트 만큼의 공간 필요
6+
*/
7+
function validTree(n: number, edges: number[][]): boolean {
8+
// 간선 개수 체크: 트리는 노드 개수 - 1개의 간선을 가져야 함
9+
if (edges.length !== n - 1) return false;
10+
11+
// 인접 리스트
12+
const adjList: Map<number, number[]> = new Map();
13+
for (let i = 0; i < n; i++) {
14+
adjList.set(i, []);
15+
}
16+
17+
// 양방향 그래프 구성
18+
for (const [u, v] of edges) {
19+
adjList.get(u)!.push(v);
20+
adjList.get(v)!.push(u);
21+
}
22+
23+
const queue: [number, number][] = [[0, -1]]; // [노드, 부모노드]
24+
const visited: Set<number> = new Set([0]);
25+
26+
while (queue.length > 0) {
27+
const [node, parent] = queue.shift()!;
28+
29+
// 모든 이웃 노드 확인
30+
for (const neighbor of adjList.get(node)!) {
31+
// 부모 노드는 continue
32+
if (neighbor === parent) continue;
33+
34+
// 이미 방문한 노드를 만나면 사이클 존재
35+
if (visited.has(neighbor)) return false;
36+
37+
// 이웃 노드를 큐에 추가하고 방문 표시
38+
visited.add(neighbor);
39+
queue.push([neighbor, node]);
40+
}
41+
}
42+
43+
// 모든 노드가 연결되어 있는지 확인
44+
return visited.size === n;
45+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""
2+
Solution: BFS
3+
Time: O(n)
4+
Space: O(n)
5+
"""
6+
7+
8+
class Solution:
9+
def maxDepth(self, root: Optional[TreeNode]) -> int:
10+
if not root:
11+
return 0
12+
13+
q = deque([root])
14+
maxLevel = 0
15+
while q:
16+
maxLevel += 1
17+
for i in range(len(q)):
18+
node = q.popleft()
19+
if node.left:
20+
q.append(node.left)
21+
if node.right:
22+
q.append(node.right)
23+
return maxLevel
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Constraints:
3+
- The number of nodes in the tree is in the range [0, 10^4].
4+
- -100 <= Node.val <= 100
5+
6+
Time Complexity: O(N)
7+
- N은 트리의 노드 수
8+
- 모든 노드를 한 번씩 방문하기 때문
9+
10+
Space Complexity: O(H)
11+
- H는 트리의 높이
12+
- 재귀 호출로 인한 호출 스택의 최대 깊이가 트리의 높이와 같음
13+
14+
풀이방법:
15+
1. Base case: root가 None인 경우 0을 반환
16+
2. 재귀를 활용하여 왼쪽과 오른쪽 서브트리 깊이를 각각 계산
17+
3. 두 서브트리의 깊이 중 최대값에 1을 더해서 반환 (현재 노드의 깊이를 포함)
18+
"""
19+
# Definition for a binary tree node.
20+
# class TreeNode:
21+
# def __init__(self, val=0, left=None, right=None):
22+
# self.val = val
23+
# self.left = left
24+
# self.right = right
25+
26+
# Solution 1: 재귀
27+
class Solution:
28+
def maxDepth(self, root: Optional[TreeNode]) -> int:
29+
if root is None:
30+
return 0
31+
32+
left_depth = self.maxDepth(root.left)
33+
right_depth = self.maxDepth(root.right)
34+
35+
return max(left_depth, right_depth) + 1
36+
37+
# Solution 2: 반복문
38+
class Solution:
39+
def maxDepth(self, root: Optional[TreeNode]) -> int:
40+
if root is None:
41+
return 0
42+
43+
stack = [(root, 1)]
44+
max_depth = 0
45+
46+
while stack:
47+
current, depth = stack.pop()
48+
49+
max_depth = max(max_depth, depth)
50+
51+
if current.left:
52+
stack.append((current.left, depth + 1))
53+
if current.right:
54+
stack.append((current.right, depth + 1))
55+
56+
return max_depth

0 commit comments

Comments
 (0)