Skip to content

Commit 7414fac

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 125a14c + b14e4d9 commit 7414fac

File tree

42 files changed

+1727
-0
lines changed

Some content is hidden

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

42 files changed

+1727
-0
lines changed

course-schedule/HC-kang.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* https://leetcode.com/problems/course-schedule/
3+
* T.C. O(V + E)
4+
* S.C. O(V + E)
5+
*/
6+
function canFinish(numCourses: number, prerequisites: number[][]): boolean {
7+
const graph: number[][] = Array.from({ length: numCourses }, () => []);
8+
for (const [course, pre] of prerequisites) {
9+
graph[pre].push(course);
10+
}
11+
12+
const visited = new Array(numCourses).fill(false);
13+
const visiting = new Array(numCourses).fill(false);
14+
15+
const dfs = (course: number): boolean => {
16+
if (visited[course]) return true;
17+
if (visiting[course]) return false;
18+
19+
visiting[course] = true;
20+
for (const neighbor of graph[course]) {
21+
if (!dfs(neighbor)) return false;
22+
}
23+
visiting[course] = false;
24+
visited[course] = true;
25+
26+
return true;
27+
};
28+
29+
for (let i = 0; i < numCourses; i++) {
30+
if (!visited[i] && !dfs(i)) return false;
31+
}
32+
33+
return true;
34+
}

course-schedule/TonyKim9401.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// TC: O(n + p)
2+
// n -> number of courses, p -> the length of prerequisites
3+
// SC: O(n + m)
4+
// n -> the length of the graph size, m -> the length of nested list's size
5+
class Solution {
6+
public boolean canFinish(int numCourses, int[][] prerequisites) {
7+
List<List<Integer>> graph = new ArrayList<>();
8+
int[] inDegree = new int[numCourses];
9+
10+
for (int i = 0; i < numCourses; i++) graph.add(new ArrayList<>());
11+
12+
for (int[] prerequisite : prerequisites) {
13+
int course = prerequisite[0];
14+
int pre = prerequisite[1];
15+
graph.get(pre).add(course);
16+
inDegree[course] += 1;
17+
}
18+
19+
Queue<Integer> q = new LinkedList<>();
20+
for (int i = 0; i < numCourses; i++) {
21+
if (inDegree[i] == 0) q.offer(i);
22+
}
23+
24+
int visitedCourses = 0;
25+
while (!q.isEmpty()) {
26+
int course = q.poll();
27+
visitedCourses += 1;
28+
29+
for (int nextCourse : graph.get(course)) {
30+
inDegree[nextCourse] -= 1;
31+
if (inDegree[nextCourse] == 0) q.offer(nextCourse);
32+
}
33+
}
34+
35+
return visitedCourses == numCourses;
36+
}
37+
}

course-schedule/flynn.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
풀이
3+
- 각 course를 node로 생각하고, prerequisite 관계에 있는 node를 간선으로 이어주면 단방향 간선으로 연결된 node 집합의 graph를 떠올릴 수 있습니다
4+
- 이 문제는 위에서 설명한 graph에 loop가 있냐 없느냐를 판단하는 문제입니다
5+
- 함수의 재귀호출 및 백트래킹을 이용해서 풀이할 수 있습니다
6+
7+
Big O
8+
- N: 과목 수 (node의 개수)
9+
- M: 배열 prerequisites의 길이 (간선의 개수)
10+
- Time compleixty: O(N + M)
11+
- prereqMap을 초기화 -> O(M)
12+
- 함수의 재귀호출을 통해 우리는 각 node를 최대 한번씩 조회합니다 -> O(N)
13+
- Space complexity: O(N + M)
14+
- prereqMap -> O(M)
15+
- checkingSet, checkedSet -> O(N)
16+
*/
17+
18+
func canFinish(numCourses int, prerequisites [][]int) bool {
19+
// 주어진 prerequisites 배열로 `a_i: b_0, b_1, ...` 형태의 맵을 짭니다
20+
prereqMap := make(map[int][]int, numCourses)
21+
for _, pair := range prerequisites {
22+
prereqMap[pair[0]] = append(prereqMap[pair[0]], pair[1])
23+
}
24+
25+
// checkingSet으로 현재 탐색하고 있는 구간에 loop가 생겼는지 여부를 판단하고, checkedSet으로 이미 탐색한 node인지를 판단합니다
26+
checkingSet, checkedSet := make(map[int]bool, 0), make(map[int]bool, 0)
27+
28+
// 특정 과목 c를 듣기 위한 선행 과목들을 탐색했을 때 loop가 생기는지 여부를 판단하는 함수입니다
29+
// (Go 언어 특성상 L:20-21 처럼 함수를 선언합니다 (함수 내부에서 함수를 선언할 땐 익명 함수를 사용 + 해당 함수를 재귀호출하기 위해서 선언과 초기화를 분리))
30+
var checkLoop func(int) bool // loop가 있다면 true
31+
checkLoop = func(c int) bool {
32+
// 과목 c가 현재 탐색하고 있는 구간에 존재한다면 loop가 있다고 판단 내릴 수 있습니다
33+
_, checkingOk := checkingSet[c]
34+
if checkingOk {
35+
return true
36+
}
37+
// 과목 c가 이미 탐색이 완료된 과목이라면 과목 c를 지나는 하위 구간에는 loop가 없다고 판단할 수 있습니다
38+
_, checkedOk := checkedSet[c]
39+
if checkedOk {
40+
return false
41+
}
42+
// 과목 c를 checkingSet에 추가합니다
43+
// 만약 하위 구간에서 과목 c를 다시 만난다면 loop가 있다고 판단할 수 있습니다
44+
checkingSet[c] = true
45+
// 각 선행과목 별로 하위구간을 만들어 탐색을 진행합니다
46+
// 하위구간 중 하나라도 loop가 발생하면 현재 구간에는 loop가 있다고 판단할 수 있습니다
47+
for _, prereq := range prereqMap[c] {
48+
if checkLoop(prereq) {
49+
return true
50+
}
51+
}
52+
// 만약 loop가 발견되지 않았다면 checkedSet에 과목 c를 추가함으로써 과목 c를 지나는 구간이 안전하다고 표시합니다
53+
checkedSet[c] = true
54+
// checkingSet에서 과목 c를 지워줍니다
55+
delete(checkingSet, c)
56+
return false
57+
}
58+
59+
for i := 0; i < numCourses; i++ {
60+
if checkLoop(i) {
61+
return false
62+
}
63+
}
64+
return true
65+
}

course-schedule/haklee.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""TC: O(node + edge), SC: O(node + edge)
2+
3+
유명한 위상 정렬 알고리즘이므로 설명은 생략한다.
4+
"""
5+
6+
7+
class Solution:
8+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
9+
# 위상 정렬.
10+
11+
# init
12+
adj_list = [[] for _ in range(numCourses)] # SC: O(edge)
13+
in_deg = [0] * numCourses # SC: O(node)
14+
15+
for edge in prerequisites:
16+
adj_list[edge[0]].append(edge[1])
17+
in_deg[edge[1]] += 1
18+
19+
node_to_search = [i for i, v in enumerate(in_deg) if v == 0] # TC: O(node)
20+
sorted_list = []
21+
22+
# process
23+
while node_to_search:
24+
cur = node_to_search.pop() # TC: 최악의 경우 총 O(node)만큼 실행
25+
sorted_list.append(cur)
26+
for node in adj_list[cur]:
27+
in_deg[node] -= 1 # TC: 최악의 경우 총 O(edge)만큼 실행
28+
if in_deg[node] == 0:
29+
node_to_search.append(node)
30+
31+
return len(sorted_list) == numCourses

course-schedule/jdalma.kt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `course-schedule` {
7+
8+
/**
9+
* TC: O(node + edge), SC: O(node + edge)
10+
*/
11+
fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
12+
if (prerequisites.isEmpty()) return true
13+
14+
return usingTopologySort(numCourses, prerequisites)
15+
}
16+
17+
private fun usingTopologySort(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
18+
val adj = List(numCourses) { mutableListOf<Int>() }
19+
val degree = IntArray(numCourses)
20+
for (e in prerequisites) {
21+
val (course, pre) = e[0] to e[1]
22+
adj[pre].add(course)
23+
degree[course]++
24+
}
25+
26+
val queue = ArrayDeque<Int>().apply {
27+
degree.forEachIndexed { index, i ->
28+
if (i == 0) {
29+
this.add(index)
30+
}
31+
}
32+
}
33+
34+
var answer = 0
35+
while (queue.isNotEmpty()) {
36+
val now = queue.removeFirst()
37+
answer++
38+
39+
queue.addAll(adj[now].filter { --degree[it] == 0 })
40+
}
41+
42+
return answer == numCourses
43+
}
44+
45+
@Test
46+
fun `코스의 개수와 코스 간 의존성을 전달하면 코스를 완료할 수 있는지 여부를 반환한다`() {
47+
canFinish(5,
48+
arrayOf(
49+
intArrayOf(0,1),
50+
intArrayOf(0,2),
51+
intArrayOf(1,3),
52+
intArrayOf(1,4),
53+
intArrayOf(3,4)
54+
)
55+
) shouldBe true
56+
canFinish(5,
57+
arrayOf(
58+
intArrayOf(1,4),
59+
intArrayOf(2,4),
60+
intArrayOf(3,1),
61+
intArrayOf(3,2)
62+
)
63+
) shouldBe true
64+
canFinish(2, arrayOf(intArrayOf(1, 0))) shouldBe true
65+
canFinish(2, arrayOf(intArrayOf(1, 0), intArrayOf(0, 1))) shouldBe false
66+
canFinish(20,
67+
arrayOf(
68+
intArrayOf(0,10),
69+
intArrayOf(3,18),
70+
intArrayOf(5,5),
71+
intArrayOf(6,11),
72+
intArrayOf(11,14),
73+
intArrayOf(13,1),
74+
intArrayOf(15,1),
75+
intArrayOf(17,4)
76+
)
77+
) shouldBe false
78+
}
79+
}

course-schedule/kayden.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from collections import deque
2+
class Solution:
3+
# 시간복잡도: O(numCourses + prerequisites의 길이)
4+
# 공간복잡도: O(numCourses + prerequisites의 길이)
5+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
6+
7+
reachable = [0 for _ in range(numCourses)]
8+
graph = [[] for _ in range(numCourses)]
9+
10+
for a, b in prerequisites:
11+
reachable[a] += 1
12+
graph[b].append(a)
13+
14+
q = deque()
15+
visited = set()
16+
for i in range(numCourses):
17+
if reachable[i] == 0:
18+
q.append(i)
19+
visited.add(i)
20+
21+
while q:
22+
node = q.popleft()
23+
24+
for next_node in graph[node]:
25+
reachable[next_node] -= 1
26+
if next_node not in visited and reachable[next_node] == 0:
27+
q.append(next_node)
28+
visited.add(next_node)
29+
30+
if len(visited) == numCourses:
31+
return True
32+
33+
return False

course-schedule/sunjae95.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @description
3+
* memoization + dfs
4+
*
5+
* n = length of nums
6+
* p = length of prerequisites
7+
*
8+
* time complexity: O(n)
9+
* space complexity: O(p)
10+
*/
11+
var canFinish = function (numCourses, prerequisites) {
12+
const memo = Array.from({ length: numCourses + 1 }, () => false);
13+
const visited = Array.from({ length: numCourses + 1 }, () => false);
14+
// graph setting
15+
const graph = prerequisites.reduce((map, [linkedNode, current]) => {
16+
const list = map.get(current) ?? [];
17+
list.push(linkedNode);
18+
map.set(current, list);
19+
return map;
20+
}, new Map());
21+
22+
const dfs = (current) => {
23+
const linkedNode = graph.get(current);
24+
25+
if (memo[current] || !linkedNode || linkedNode.length === 0) return true;
26+
27+
for (const node of linkedNode) {
28+
if (visited[node]) return false;
29+
30+
visited[node] = true;
31+
if (!dfs(node)) return false;
32+
visited[node] = false;
33+
memo[node] = true;
34+
}
35+
36+
return true;
37+
};
38+
39+
for (const [current] of graph) {
40+
visited[current] = true;
41+
if (!dfs(current)) return false;
42+
visited[current] = false;
43+
memo[current] = true;
44+
}
45+
46+
return true;
47+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// 시간복잡도: O(log n)
2+
// 공간복잡도: O(1)
3+
4+
/**
5+
* @param {number[]} nums
6+
* @return {number}
7+
*/
8+
var findMin = function(nums) {
9+
let leftIdx = 0;
10+
let rightIdx = nums.length - 1;
11+
12+
if (nums.length === 1) return nums[0]
13+
14+
while (leftIdx <= rightIdx) {
15+
if (nums[leftIdx] < nums[rightIdx]) return nums[leftIdx]
16+
17+
let midIdx = Math.floor((leftIdx + rightIdx) / 2);
18+
19+
if (nums[midIdx] > nums[midIdx+1]) {
20+
return nums[midIdx+1]
21+
}
22+
23+
if (nums[leftIdx] < nums[midIdx] && nums[leftIdx] > nums[rightIdx]) {
24+
leftIdx = midIdx
25+
} else {
26+
rightIdx = midIdx
27+
}
28+
}
29+
30+
return nums[0]
31+
};
32+

0 commit comments

Comments
 (0)