Skip to content

Commit 046ac88

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 51f119d + 68044c0 commit 046ac88

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+3485
-38
lines changed

β€Žclone-graph/forest000014.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void dfs(Node oldNode) {
7070
Node newNeighbor = createNode(oldNeighbor.val);
7171
newNode.neighbors.add(newNeighbor);
7272
newNeighbor.neighbors.add(newNode);
73-
dfs(oldNeighbor, newNeighbor);
73+
dfs(oldNeighbor);
7474
}
7575
}
7676
}

β€Žcourse-schedule/dusunax.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
'''
2+
# 207
3+
μ°Έκ³  μ˜μƒ: https://www.youtube.com/watch?v=EgI5nU9etnU
4+
문제 풀이: https://www.algodale.com/problems/course-schedule/
5+
6+
## 문제 정리
7+
πŸ‘‰ prerequisitesλž€? ν•„μˆ˜ μ„ μˆ˜ κ³Όλͺ©μ΄λ‹€.
8+
πŸ‘‰ λ°©ν–₯성이 μžˆλŠ” μ—°κ²° κ΄€κ³„μ΄λ―€λ‘œ, Directed Graphλ‹€.
9+
πŸ‘‰ Cycle λ°œμƒ μ‹œ, μ½”μŠ€λ₯Ό μ΄μˆ˜ν•  수 μ—†λ‹€.(μ„œλ‘œ μ˜μ‘΄ν•˜λŠ” μˆœν™˜μ΄ μžˆμ–΄μ„œ 끝없이 돌게 λ˜λŠ” 경우)
10+
11+
## ν•΄κ²° 방식 두가지
12+
1. BFS, Queue, Topological Sort: μœ„μƒ μ •λ ¬
13+
2. DFS, Cycle Detection: μˆœν™˜ 탐지
14+
15+
### μœ„μƒ μ •λ ¬(Topological Sort) - BFS, Queue
16+
- μ§„μž… 차수(indegree): λ…Έλ“œλ‘œ λ“€μ–΄μ˜€λŠ” ν™”μ‚΄ν‘œ 수
17+
- κ·Έλž˜ν”„λ‘œ 인접 리슀트 ꡬ성
18+
- Queue에 λ„£κΈ°
19+
- Queue BFS 탐색
20+
- λͺ¨λ“  κ³Όλͺ©μ„ λ“€μ—ˆλŠ”μ§€ 확인
21+
22+
### μˆœν™˜ 탐지(Cycle Detection) - DFS
23+
- κ·Έλž˜ν”„λ‘œ 인접 리슀트 ꡬ성
24+
- λ°©λ¬Έ μƒνƒœ λ°°μ—΄ μ΄ˆκΈ°ν™”
25+
- dfs ν•¨μˆ˜
26+
- λͺ¨λ“  λ…Έλ“œμ— λŒ€ν•΄ dfs μ‹€ν–‰
27+
28+
## TC & SC
29+
- μ‹œκ°„ λ³΅μž‘λ„μ™€ 곡간 λ³΅μž‘λ„λŠ” O(V + E)둜 λ™μΌν•˜λ‹€.
30+
```
31+
V: λ…Έλ“œ 수(κ³Όλͺ© 수)
32+
E: κ°„μ„  수(μ„ μˆ˜ κ³Όλͺ© 관계 수)
33+
```
34+
35+
### TC is O(V + E)
36+
37+
두 방법 λͺ¨λ‘, κ·Έλž˜ν”„μ˜ λͺ¨λ“  λ…Έλ“œμ™€ 간선을 ν•œ λ²ˆμ”© 확인함
38+
- BFS: λͺ¨λ“  Vλ₯Ό μˆœνšŒν•˜λ©΄μ„œ, 각 λ…Έλ“œμ—μ„œ λ‚˜κ°€λŠ” Eλ₯Ό 따라가며 차수λ₯Ό μ€„μž„
39+
- DFS: λͺ¨λ“  Vλ₯Ό μˆœνšŒν•˜λ©΄μ„œ, 각 λ…Έλ“œμ—μ„œ μ—°κ²°λœ Eλ₯Ό 따라가며 깊이 탐색
40+
41+
### SC is O(V + E)
42+
- O(V+E): V + Eλ₯Ό μ €μž₯ν•˜λŠ” 인접 리슀트 κ·Έλž˜ν”„
43+
- O(V)'s: λ°©λ¬Έ μƒνƒœ μ €μž₯, μ§„μž… 차수 λ°°μ—΄, BFS 큐, DFS 호좜 μŠ€νƒ
44+
45+
## μœ„μƒμ •λ ¬(BFS) vs μˆœν™˜νƒμ§€(DFS)πŸ€”
46+
47+
### BFSλ₯Ό μ‚¬μš©ν–ˆμ„ λ•Œ
48+
- λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•œ BFSκ°€ indegree(μ§„μž…μ°¨μˆ˜) κ°œλ…μ΄ 보닀 μ§κ΄€μ μ΄λ―€λ‘œ => "μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•  수 μžˆλŠ”μ§€ 확인"ν•  λ•Œ λͺ…ν™•ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ‹€. μ§„μž… μ°¨μˆ˜κ°€ 0인 λ…Έλ“œλΆ€ν„° μ‹œμž‘ν•΄μ„œ 처리
49+
- μ„ μˆ˜ κ³Όλͺ©μ„ λ‹€ 듀은 κ³Όλͺ©μ€ μ§„μž… μ°¨μˆ˜κ°€ 0이 λ˜λ―€λ‘œ λ“€μ–΄κ°ˆ 수 μžˆλŠ” κ³Όλͺ©μ΄λΌλŠ” 점이 λͺ…확함
50+
```
51+
ν‚€μ›Œλ“œ: 처리 μˆœμ„œλ₯Ό 좜λ ₯, μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•  수 μžˆλŠ”μ§€
52+
```
53+
54+
### DFSλ₯Ό μ‚¬μš©ν–ˆμ„ λ•Œ
55+
- DFS μˆœν™˜ νƒμ§€λŠ” "μˆœν™˜ μ—¬λΆ€"κ°€ 핡심일 λ•Œ μžμ—°μŠ€λŸ½λ‹€.
56+
- μƒνƒœ(Status)λ₯Ό μ‚¬μš©ν•΄μ„œ, λ°©λ¬Έ 쀑인 λ…Έλ“œ μƒνƒœλ₯Ό λ‹€μ‹œ λ°©λ¬Έν•œλ‹€λ©΄ μˆœν™˜μ΄ μžˆμŒμ„ λ°”λ‘œ μ•Œ 수 μžˆλ‹€.
57+
- μˆœν™˜μ΄ 발견되면 λ°”λ‘œ μ€‘λ‹¨ν•˜λ―€λ‘œ, μˆœν™˜ 탐지에 μžμ—°μŠ€λŸ½λ‹€.
58+
```
59+
ν‚€μ›Œλ“œ: 사이클이 μžˆλŠ”μ§€ νŒλ‹¨
60+
```
61+
62+
### +a) `@cache`λ₯Ό ν™œμš©ν•΄λ³΄μž.
63+
- νŒŒμ΄μ„  3.9~ λ©”λͺ¨μ΄μ œμ΄μ…˜ ν•¨μˆ˜
64+
- 순수 ν•¨μˆ˜ + μž¬κ·€ μ΅œμ ν™”μ— μ‚¬μš© (μ™ΈλΆ€ μ˜μ‘΄μ„±, λΆ€μˆ˜νš¨κ³Όμ— μ£Όμ˜ν•  것)
65+
'''
66+
from enum import Enum
67+
68+
class Status(Enum): # use it to dfs
69+
INITIAL = 1
70+
IN_PROGRESS = 2
71+
FINISHED = 3
72+
73+
class Solution:
74+
'''
75+
1. BFS
76+
μœ„μƒ μ •λ ¬
77+
'''
78+
def canFinishTopologicalSort(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
79+
indegree = [0] * numCourses
80+
graph = defaultdict(list)
81+
82+
for dest, src in prerequisites:
83+
graph[src].append(dest)
84+
indegree[dest] += 1
85+
86+
queue = deque([i for i in range(numCourses) if indegree[i] == 0])
87+
processed_count = 0
88+
89+
while queue:
90+
node = queue.popleft()
91+
processed_count += 1
92+
for neighbor in graph[node]:
93+
indegree[neighbor] -= 1
94+
if indegree[neighbor] == 0:
95+
queue.append(neighbor)
96+
97+
return processed_count == numCourses
98+
99+
'''
100+
2. DFS
101+
μˆœν™˜ 탐지
102+
'''
103+
def canFinishCycleDetection(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
104+
graph = defaultdict(list)
105+
106+
for dest, src in prerequisites:
107+
graph[src].append(dest)
108+
109+
statuses = {i: Status.INITIAL for i in range(numCourses)}
110+
111+
def dfs(node):
112+
if statuses[node] == Status.IN_PROGRESS:
113+
return False
114+
if statuses[node] == Status.FINISHED:
115+
return True
116+
117+
statuses[node] = Status.IN_PROGRESS
118+
for neighbor in graph[node]:
119+
if not dfs(neighbor):
120+
return False
121+
statuses[node] = Status.FINISHED
122+
return True
123+
124+
return all(dfs(crs) for crs in range(numCourses))
125+
126+
'''
127+
3. @cache
128+
129+
파이썬 3.9 μ΄μƒμ—μ„œ μ‚¬μš©ν•˜λŠ” λ©”λͺ¨μ΄μ œμ΄μ…˜ λ°μ½”λ ˆμ΄ν„°
130+
- 동일 μž…λ ₯ -> 동일 좜λ ₯을 보μž₯ν•œλ‹€.
131+
- 128개 κΉŒμ§€λ§Œ μ €μž₯ν•˜λŠ” @lru_cache도 μžˆλ‹€.
132+
'''
133+
def canFinishWithCache(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
134+
graph = defaultdict(list)
135+
136+
for dest, src in prerequisites:
137+
graph[src].append(dest)
138+
139+
traversing = set()
140+
141+
@cache
142+
def dfs(node):
143+
if node in traversing:
144+
return False
145+
146+
traversing.add(node)
147+
result = all(dfs(pre) for pre in graph[node])
148+
traversing.remove(node)
149+
return result
150+
151+
return all(dfs(node) for node in range(numCourses))
152+
153+
'''
154+
4. visitedκ³Ό ν•¨κ»˜ μ‚¬μš©ν•˜κΈ°
155+
156+
@cache λ°μ½”λ ˆμ΄ν„°λŠ” λ©”λͺ¨μ΄μ œμ΄μ…˜, 같은 μž…λ ₯값에 따라 같은 κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜κ²Œν•¨
157+
κ²°κ³Όκ°€ λ³€ν•˜μ§€ μ•Šμ„ λ•Œ μœ μš©ν•¨ => dfs(node)λŠ” μ™ΈλΆ€ μƒνƒœ μˆœν™˜ traversing에 μ˜μ‘΄ν•΄μ„œ λ™μž‘μ΄ λ‹¬λΌμ§ˆ 수 μžˆλ‹€.
158+
λ”°λΌμ„œ visited set이 더 μžμ—°μŠ€λŸ¬μšΈ 수 μžˆλ‹€
159+
'''
160+
def canFinishWithVisited(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
161+
graph = defaultdict(list)
162+
163+
for dest, src in prerequisites:
164+
graph[src].append(dest)
165+
166+
traversing = set()
167+
visited = set()
168+
169+
def dfs(node):
170+
if node in traversing:
171+
return False
172+
if node in visited:
173+
return True
174+
175+
traversing.add(node)
176+
for pre in graph[node]:
177+
if not dfs(pre):
178+
return False
179+
traversing.remove(node)
180+
181+
visited.add(node)
182+
return True
183+
184+
return all(dfs(i) for i in range(numCourses))

β€Žcourse-schedule/eunhwa99.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import java.util.ArrayList;
2+
import java.util.LinkedList;
3+
import java.util.List;
4+
import java.util.Queue;
5+
6+
class Solution {
7+
8+
// TC: O(numCourses + E) EλŠ” prerequisites λ°°μ—΄μ˜ 길이 (즉, κ°„μ„ μ˜ 개수).
9+
// SC: O(numCourses + E)
10+
public boolean canFinish(int numCourses, int[][] prerequisites) {
11+
int[] inDegree = new int[numCourses];
12+
List<List<Integer>> adj = new ArrayList<>();
13+
14+
for (int i = 0; i < numCourses; i++) {
15+
adj.add(new ArrayList<>());
16+
}
17+
18+
for (int[] pre : prerequisites) {
19+
adj.get(pre[1]).add(pre[0]);
20+
inDegree[pre[0]]++;
21+
}
22+
23+
Queue<Integer> queue = new LinkedList<>();
24+
for (int i = 0; i < numCourses; i++) {
25+
if (inDegree[i] == 0) {
26+
queue.add(i);
27+
}
28+
}
29+
for (int i = 0; i < numCourses; i++) {
30+
if (queue.isEmpty()) {
31+
return false;
32+
}
33+
int course = queue.poll();
34+
35+
for (int nextCourse : adj.get(course)) {
36+
inDegree[nextCourse]--;
37+
if (inDegree[nextCourse] == 0) {
38+
queue.add(nextCourse);
39+
}
40+
}
41+
}
42+
return queue.isEmpty();
43+
}
44+
}
45+

β€Žcourse-schedule/gwbaik9717.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// n: numCourses, p: len(prerequisites)
2+
// Time complexity: O(n + p)
3+
// Space complexity: O(n + p)
4+
5+
class _Queue {
6+
constructor() {
7+
this.q = [];
8+
this.start = 0;
9+
this.end = 0;
10+
}
11+
12+
isEmpty() {
13+
return this.start === this.end;
14+
}
15+
16+
push(value) {
17+
this.q.push(value);
18+
this.end++;
19+
}
20+
21+
shift() {
22+
const rv = this.q[this.start];
23+
delete this.q[this.start++];
24+
25+
return rv;
26+
}
27+
}
28+
29+
/**
30+
* @param {number} numCourses
31+
* @param {number[][]} prerequisites
32+
* @return {boolean}
33+
*/
34+
var canFinish = function (numCourses, prerequisites) {
35+
const graph = Array.from({ length: numCourses }, () => []);
36+
const inDegree = Array.from({ length: numCourses }, () => 0);
37+
38+
for (const [end, start] of prerequisites) {
39+
graph[start].push(end);
40+
inDegree[end]++;
41+
}
42+
43+
const q = new _Queue();
44+
45+
for (let i = 0; i < numCourses; i++) {
46+
if (inDegree[i] === 0) {
47+
q.push(i);
48+
}
49+
}
50+
51+
let count = 0;
52+
53+
while (!q.isEmpty()) {
54+
const current = q.shift();
55+
count++;
56+
57+
// ν˜„μž¬ λ…Έλ“œμ™€ μ—°κ²°λœ λ‹€λ₯Έ λ…Έλ“œμ˜ 차수 κ°μ†Œ
58+
for (const node of graph[current]) {
59+
inDegree[node] -= 1;
60+
61+
if (inDegree[node] === 0) {
62+
q.push(node);
63+
}
64+
}
65+
}
66+
67+
return count === numCourses;
68+
};

β€Žcourse-schedule/mmyeon.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @link https://leetcode.com/problems/course-schedule/description/
3+
*
4+
* μ ‘κ·Ό 방법 :
5+
* - μ£Όμ–΄μ§„ κ³Όλͺ©μ—μ„œ μ„ μˆ˜ κ³Όλͺ© 사이클이 μ‘΄μž¬ν•˜λŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄μ„œ dfs μ‚¬μš©
6+
* - 사이클이 μžˆλ‹€λŠ” 건 탐색 쀑에 λ‹€μ‹œ 동일 κ³Όλͺ©μ΄ λ“±μž₯ν•œ κ²½μš°λ‹ˆκΉŒ, κ³Όλͺ©λ³„ κ²°κ³Ό μ €μž₯ν•˜κΈ° μœ„ν•΄μ„œ visited λ°°μ—΄ μ‚¬μš©
7+
*
8+
* μ‹œκ°„λ³΅μž‘λ„ : O(n + e)
9+
* - n = λ“€μ–΄μ•Ό ν•˜λŠ” κ³Όλͺ© 수
10+
* - e = μ„ μˆ˜ κ³Όλͺ©κ³Ό μ—°κ²°λœ κ³Όλͺ© 수
11+
* - μ„ μˆ˜ κ³Όλͺ© dfs ν˜ΈμΆœν•˜κ³ , μ„ μˆ˜ κ³Όλͺ©κ³Ό μ—°κ²°λœ κ³Όλͺ©λ„ ν˜ΈμΆœν•¨
12+
*
13+
* κ³΅κ°„λ³΅μž‘λ„ : O(n + e)
14+
* - n = λ“€μ–΄μ•Ό ν•˜λŠ” κ³Όλͺ© 수
15+
* - e = μ„ μˆ˜ κ³Όλͺ©κ³Ό μ—°κ²°λœ κ³Όλͺ© 수
16+
* - visited λ°°μ—΄ : O(n)
17+
* - Map : O(e)
18+
*/
19+
20+
function canFinish(numCourses: number, prerequisites: number[][]): boolean {
21+
// μ„ μˆ˜ κ³Όλͺ©μ„ ν‚€, 후속 κ³Όλͺ©μ„ κ°’μœΌλ‘œ μ €μž₯
22+
const map = new Map<number, number[]>();
23+
24+
for (const [course, prerequisite] of prerequisites) {
25+
if (!map.has(prerequisite)) map.set(prerequisite, []);
26+
map.get(prerequisite)!.push(course);
27+
}
28+
29+
// 이미 탐색쀑인 κ³Όλͺ©μΈμ§€ ν™•μΈν•˜κΈ° μœ„ν•œ λ°°μ—΄
30+
// 미탐색 : 0, 탐색쀑: 1, νƒμƒ‰μ™„λ£Œ : 2둜 처리
31+
const visited = Array(numCourses).fill(0);
32+
33+
const dfs = (course: number) => {
34+
// 탐색쀑이면 사이클이 λ°œμƒ
35+
if (visited[course] === 1) return false;
36+
// 탐색 μ™„λ£ŒμΈ κ³Όλͺ©μ€ 사이클이 μ—†λŠ” μƒνƒœλ‹ˆκΉŒ true 리턴
37+
if (visited[course] === 2) return true;
38+
39+
// 탐색 μ‹œμž‘
40+
// 탐색 쀑인 μƒνƒœλ‘œ λ³€κ²½
41+
visited[course] = 1;
42+
43+
const nextCourses = map.get(course) ?? [];
44+
45+
// 후속 κ³Όλͺ© λͺ¨λ‘ 체크
46+
for (const nextCourse of nextCourses) {
47+
if (!dfs(nextCourse)) return false;
48+
}
49+
50+
// 탐색 μ™„λ£Œ μƒνƒœλ‘œ λ³€κ²½
51+
visited[course] = 2;
52+
return true;
53+
};
54+
55+
// λ“€μ–΄μ•Ό ν•˜λŠ” λͺ¨λ“  κ³Όλͺ©μ— λŒ€ν•΄ dfs 호좜
56+
for (let i = 0; i < numCourses; i++) {
57+
// 미탐색 λ…Έλ“œλ§Œ νƒμƒ‰ν•˜λ„λ‘ 처리
58+
if (visited[i] === 0 && !dfs(i)) return false;
59+
}
60+
61+
return true;
62+
}

0 commit comments

Comments
Β (0)