Skip to content

Commit 1800ddc

Browse files
authored
Merge pull request #1011 from mmyeon/main
[mallayon] Week 10
2 parents 2dc5135 + e9d57a6 commit 1800ddc

File tree

5 files changed

+267
-0
lines changed

5 files changed

+267
-0
lines changed

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+
}

invert-binary-tree/mmyeon.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
class TreeNode {
2+
val: number;
3+
left: TreeNode | null;
4+
right: TreeNode | null;
5+
constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
6+
this.val = val === undefined ? 0 : val;
7+
this.left = left === undefined ? null : left;
8+
this.right = right === undefined ? null : right;
9+
}
10+
}
11+
12+
/**
13+
* @link https://leetcode.com/problems/invert-binary-tree/description/
14+
*
15+
* 접근 방법 : 깊이 우선 탐색(DFS) 사용
16+
* - 각 노드의 좌우 자식 노드 swap 진행
17+
* - 왼쪽, 오른쪽 서브트리에 대해 재귀적으로 호출
18+
*
19+
* 시간복잡도 : O(n)
20+
* - n은 노드의 개수, 주어진 노드 만큼 순회
21+
*
22+
* 공간복잡도 : O(h)
23+
* - h : 트리의 높이
24+
* - 호출 스택 최대 트리 높이만큼 쌓임
25+
*/
26+
function invertTree(root: TreeNode | null): TreeNode | null {
27+
if (!root) return root;
28+
29+
[root.left, root.right] = [root.right, root.left];
30+
invertTree(root.left);
31+
invertTree(root.right);
32+
33+
return root;
34+
}
35+
36+
/**
37+
*
38+
* 접근 방법 : 너비 우선 탐색(BFS) 사용
39+
* - root 노드를 큐에 담고, 큐가 빌 때까지 좌우 자식 노드 swap과 큐에 추가 하는 로직 반복하기
40+
*
41+
* 시간복잡도 : O(n)
42+
* - n: 트리 노드의 개수
43+
* - 모든 노드를 한 번 씩 방문하고 swap 작업 진행
44+
*
45+
* 공간복잡도 : O(n)
46+
* - 최악의 경우 치우친 트리인 경우 모든 노드 순차적으로 큐에 저장
47+
*/
48+
function invertTree(root: TreeNode | null): TreeNode | null {
49+
if (!root) return root;
50+
51+
const queue = [root];
52+
53+
while (queue.length) {
54+
const node = queue.shift()!;
55+
56+
[node.left, node.right] = [node.right, node.left];
57+
58+
if (node.left) queue.push(node.left);
59+
if (node.right) queue.push(node.right);
60+
}
61+
62+
return root;
63+
}

jump-game/mmyeon.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
*@link https://leetcode.com/problems/jump-game/description/
3+
*
4+
* 접근 방법 :
5+
* - 현재 인덱스에서 최대로 도달할 수 있는 인덱스를 갱신하여 마지막 인덱스에 도달할 수 있는지 체크
6+
* - 최대 도달할 수 있는 인덱스가 현재 인덱스보다 작으면, 이후는 확인할 필요 없으니까 false 리턴
7+
*
8+
* 시간복잡도 : O(n)
9+
* - n = 배열의 길이, 배열 1회만 순회
10+
*
11+
* 공간복잡도 : O(1)
12+
* - 고정된 변수만 사용
13+
*/
14+
15+
function canJump(nums: number[]): boolean {
16+
const lastIndex = nums.length - 1;
17+
let maxReachableIndex = 0;
18+
19+
for (let i = 0; i < nums.length; i++) {
20+
if (maxReachableIndex < i) return false;
21+
22+
maxReachableIndex = Math.max(maxReachableIndex, i + nums[i]);
23+
24+
if (lastIndex <= maxReachableIndex) return true;
25+
}
26+
27+
return false;
28+
}

merge-k-sorted-lists/mmyeon.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
class ListNode {
2+
val: number;
3+
next: ListNode | null;
4+
constructor(val?: number, next?: ListNode | null) {
5+
this.val = val === undefined ? 0 : val;
6+
this.next = next === undefined ? null : next;
7+
}
8+
}
9+
10+
/**
11+
* @link https://leetcode.com/problems/merge-k-sorted-lists/description/
12+
*
13+
* 접근 방법 :
14+
* - 리스트를 배열에 넣고, 최소값을 가진 노드 찾기
15+
* - 최소값 노드를 더미 노드에 연결한 뒤 제거하고, 최소값 노드의 다음 노드를 다시 배열에 추가하기
16+
* - 배열 길이가 0이 될 때까지 반복하기
17+
*
18+
* 시간복잡도 : O(n * k)
19+
* - n = 총 노드의 개수
20+
* - k = 리스트의 개수
21+
* - 최소값 찾고, 최소값 제거하는 로직: O(k)
22+
* - 위의 연산을 총 n번 실행
23+
*
24+
* 공간복잡도 : O(k)
25+
* - k = 리스트 개수
26+
* - minList 배열의 크기가 최대 K개까지 유지
27+
*
28+
*/
29+
30+
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
31+
const minList: ListNode[] = [];
32+
33+
for (const list of lists) {
34+
if (list !== null) minList.push(list);
35+
}
36+
37+
const dummy = new ListNode();
38+
let tail = dummy;
39+
40+
while (minList.length > 0) {
41+
const minIndex = getMinIndex(minList);
42+
const minNode = minList.splice(minIndex, 1)[0];
43+
44+
tail.next = minNode;
45+
tail = tail.next;
46+
47+
if (minNode.next) minList.push(minNode.next);
48+
}
49+
50+
return dummy.next;
51+
}
52+
53+
function getMinIndex(nodes: ListNode[]): number {
54+
let minIndex = 0;
55+
56+
for (let i = 1; i < nodes.length; i++) {
57+
if (nodes[i].val < nodes[minIndex].val) minIndex = i;
58+
}
59+
60+
return minIndex;
61+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @link https://leetcode.com/problems/search-in-rotated-sorted-array/description/
3+
*
4+
* 접근 방법 :
5+
* - O(log n)으로 풀어야 하니까 이진 탐색으로 탐색 범위 좁히기
6+
* - pivot 인덱스 찾고, pivot 기준으로 target이 속하는 범위에서 탐색하기
7+
*
8+
* 시간복잡도 : O(log n)
9+
* - 배열 범위를 계속 줄여나가므로 O(log n)
10+
*
11+
* 공간복잡도 : O(1)
12+
* - 고정된 변수만 사용
13+
*/
14+
15+
function search(nums: number[], target: number): number {
16+
let start = 0,
17+
end = nums.length - 1;
18+
19+
// pivot 인덱스 찾기
20+
while (start < end) {
21+
const mid = Math.floor((start + end) / 2);
22+
if (nums[mid] > nums[end]) {
23+
start = mid + 1;
24+
} else {
25+
end = mid;
26+
}
27+
}
28+
29+
const pivot = start;
30+
start = 0;
31+
end = nums.length - 1;
32+
33+
// pivot 기준으로 target이 포함된 범위로 좁히기
34+
if (nums[pivot] <= target && target <= nums[end]) {
35+
start = pivot;
36+
} else {
37+
end = pivot - 1;
38+
}
39+
40+
// target 인덱스 찾기 위해서 이진 탐색 실행
41+
while (start <= end) {
42+
const mid = Math.floor((start + end) / 2);
43+
44+
if (nums[mid] === target) return mid;
45+
if (nums[mid] < target) {
46+
start = mid + 1;
47+
} else {
48+
end = mid - 1;
49+
}
50+
}
51+
52+
return -1;
53+
}

0 commit comments

Comments
 (0)