From e9404536aaffac28ea3a20b2b2475d64e5af2aa1 Mon Sep 17 00:00:00 2001
From: mmyeon <mindfulyeon@gmail.com>
Date: Mon, 10 Feb 2025 10:27:33 +0900
Subject: [PATCH 1/5] add solution : 226. Invert Binary Tree

---
 invert-binary-tree/mmyeon.ts | 63 ++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)
 create mode 100644 invert-binary-tree/mmyeon.ts

diff --git a/invert-binary-tree/mmyeon.ts b/invert-binary-tree/mmyeon.ts
new file mode 100644
index 000000000..f3152cb9b
--- /dev/null
+++ b/invert-binary-tree/mmyeon.ts
@@ -0,0 +1,63 @@
+class TreeNode {
+  val: number;
+  left: TreeNode | null;
+  right: TreeNode | null;
+  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
+    this.val = val === undefined ? 0 : val;
+    this.left = left === undefined ? null : left;
+    this.right = right === undefined ? null : right;
+  }
+}
+
+/**
+ * @link https://leetcode.com/problems/invert-binary-tree/description/
+ *
+ * 접근 방법 : 깊이 우선 탐색(DFS) 사용
+ * - 각 노드의 좌우 자식 노드 swap 진행
+ * - 왼쪽, 오른쪽 서브트리에 대해 재귀적으로 호출
+ *
+ * 시간복잡도 : O(n)
+ *  - n은 노드의 개수, 주어진 노드 만큼 순회
+ *
+ * 공간복잡도 : O(h)
+ *  - h : 트리의 높이
+ *  - 호출 스택 최대 트리 높이만큼 쌓임
+ */
+function invertTree(root: TreeNode | null): TreeNode | null {
+  if (!root) return root;
+
+  [root.left, root.right] = [root.right, root.left];
+  invertTree(root.left);
+  invertTree(root.right);
+
+  return root;
+}
+
+/**
+ *
+ * 접근 방법 : 너비 우선 탐색(BFS) 사용
+ * - root 노드를 큐에 담고, 큐가 빌 때까지 좌우 자식 노드 swap과 큐에 추가 하는 로직 반복하기
+ *
+ * 시간복잡도 : O(n)
+ * - n: 트리 노드의 개수
+ * - 모든 노드를 한 번 씩 방문하고 swap 작업 진행
+ *
+ * 공간복잡도 : O(n)
+ *  - 최악의 경우 치우친 트리인 경우 모든 노드 순차적으로 큐에 저장
+ */
+function invertTree(root: TreeNode | null): TreeNode | null {
+  if (!root) return root;
+
+  const queue = [root];
+
+  while (queue.length) {
+    const node = queue.shift()!;
+
+    [node.left, node.right] = [node.right, node.left];
+
+    if (node.left) queue.push(node.left);
+    if (node.right) queue.push(node.right);
+  }
+
+  return root;
+}

From 00be0fcedcdf39f94870ec2663fe94c9e2921de4 Mon Sep 17 00:00:00 2001
From: mmyeon <mindfulyeon@gmail.com>
Date: Fri, 14 Feb 2025 20:16:50 +0900
Subject: [PATCH 2/5] add solution : 55. Jump Game

---
 jump-game/mmyeon.ts | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 jump-game/mmyeon.ts

diff --git a/jump-game/mmyeon.ts b/jump-game/mmyeon.ts
new file mode 100644
index 000000000..e2254bf9b
--- /dev/null
+++ b/jump-game/mmyeon.ts
@@ -0,0 +1,28 @@
+/**
+ *@link https://leetcode.com/problems/jump-game/description/
+ *
+ * 접근 방법 :
+ *  - 현재 인덱스에서 최대로 도달할 수 있는 인덱스를 갱신하여 마지막 인덱스에 도달할 수 있는지 체크
+ *  - 최대 도달할 수 있는 인덱스가 현재 인덱스보다 작으면, 이후는 확인할 필요 없으니까 false 리턴
+ *
+ * 시간복잡도 : O(n)
+ *  - n = 배열의 길이, 배열 1회만 순회
+ *
+ * 공간복잡도 : O(1)
+ *  - 고정된 변수만 사용
+ */
+
+function canJump(nums: number[]): boolean {
+  const lastIndex = nums.length - 1;
+  let maxReachableIndex = 0;
+
+  for (let i = 0; i < nums.length; i++) {
+    if (maxReachableIndex < i) return false;
+
+    maxReachableIndex = Math.max(maxReachableIndex, i + nums[i]);
+
+    if (lastIndex <= maxReachableIndex) return true;
+  }
+
+  return false;
+}

From e3a00b42653b2871ee93ba447d7e079d3d0c6c3d Mon Sep 17 00:00:00 2001
From: mmyeon <mindfulyeon@gmail.com>
Date: Fri, 14 Feb 2025 23:46:43 +0900
Subject: [PATCH 3/5] add solution : 207. Course Schedule

---
 course-schedule/mmyeon.ts | 62 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 course-schedule/mmyeon.ts

diff --git a/course-schedule/mmyeon.ts b/course-schedule/mmyeon.ts
new file mode 100644
index 000000000..0ed72dc19
--- /dev/null
+++ b/course-schedule/mmyeon.ts
@@ -0,0 +1,62 @@
+/**
+ * @link https://leetcode.com/problems/course-schedule/description/
+ *
+ * 접근 방법 :
+ *  - 주어진 과목에서 선수 과목 사이클이 존재하는지 확인하기 위해서 dfs 사용
+ *  - 사이클이 있다는 건 탐색 중에 다시 동일 과목이 등장한 경우니까, 과목별 결과 저장하기 위해서 visited 배열 사용
+ *
+ * 시간복잡도 : O(n + e)
+ *  - n = 들어야 하는 과목 수
+ *  - e = 선수 과목과 연결된 과목 수
+ *  - 선수 과목 dfs 호출하고, 선수 과목과 연결된 과목도 호출함
+ *
+ * 공간복잡도 : O(n + e)
+ *  - n = 들어야 하는 과목 수
+ *  - e = 선수 과목과 연결된 과목 수
+ *  - visited 배열 : O(n)
+ *  - Map : O(e)
+ */
+
+function canFinish(numCourses: number, prerequisites: number[][]): boolean {
+  // 선수 과목을 키, 후속 과목을 값으로 저장
+  const map = new Map<number, number[]>();
+
+  for (const [course, prerequisite] of prerequisites) {
+    if (!map.has(prerequisite)) map.set(prerequisite, []);
+    map.get(prerequisite)!.push(course);
+  }
+
+  // 이미 탐색중인 과목인지 확인하기 위한 배열
+  // 미탐색 : 0, 탐색중: 1, 탐색완료 : 2로 처리
+  const visited = Array(numCourses).fill(0);
+
+  const dfs = (course: number) => {
+    // 탐색중이면 사이클이 발생
+    if (visited[course] === 1) return false;
+    // 탐색 완료인 과목은 사이클이 없는 상태니까 true 리턴
+    if (visited[course] === 2) return true;
+
+    // 탐색 시작
+    // 탐색 중인 상태로 변경
+    visited[course] = 1;
+
+    const nextCourses = map.get(course) ?? [];
+
+    // 후속 과목 모두 체크
+    for (const nextCourse of nextCourses) {
+      if (!dfs(nextCourse)) return false;
+    }
+
+    // 탐색 완료 상태로 변경
+    visited[course] = 2;
+    return true;
+  };
+
+  // 들어야 하는 모든 과목에 대해 dfs 호출
+  for (let i = 0; i < numCourses; i++) {
+    // 미탐색 노드만 탐색하도록 처리
+    if (visited[i] === 0 && !dfs(i)) return false;
+  }
+
+  return true;
+}

From 4d28d87d03c9856f78223bf5d9a4f42f91abff8c Mon Sep 17 00:00:00 2001
From: mmyeon <mindfulyeon@gmail.com>
Date: Sat, 15 Feb 2025 21:25:35 +0900
Subject: [PATCH 4/5] add solution : 33. Search in Rotated Sorted Array

---
 search-in-rotated-sorted-array/mmyeon.ts | 53 ++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 search-in-rotated-sorted-array/mmyeon.ts

diff --git a/search-in-rotated-sorted-array/mmyeon.ts b/search-in-rotated-sorted-array/mmyeon.ts
new file mode 100644
index 000000000..04ed50d71
--- /dev/null
+++ b/search-in-rotated-sorted-array/mmyeon.ts
@@ -0,0 +1,53 @@
+/**
+ * @link https://leetcode.com/problems/search-in-rotated-sorted-array/description/
+ *
+ * 접근 방법 :
+ *  - O(log n)으로 풀어야 하니까 이진 탐색으로 탐색 범위 좁히기
+ *  - pivot 인덱스 찾고, pivot 기준으로 target이 속하는 범위에서 탐색하기
+ *
+ * 시간복잡도 : O(log n)
+ *  - 배열 범위를 계속 줄여나가므로 O(log n)
+ *
+ * 공간복잡도 : O(1)
+ *  - 고정된 변수만 사용
+ */
+
+function search(nums: number[], target: number): number {
+  let start = 0,
+    end = nums.length - 1;
+
+  // pivot 인덱스 찾기
+  while (start < end) {
+    const mid = Math.floor((start + end) / 2);
+    if (nums[mid] > nums[end]) {
+      start = mid + 1;
+    } else {
+      end = mid;
+    }
+  }
+
+  const pivot = start;
+  start = 0;
+  end = nums.length - 1;
+
+  // pivot 기준으로 target이 포함된 범위로 좁히기
+  if (nums[pivot] <= target && target <= nums[end]) {
+    start = pivot;
+  } else {
+    end = pivot - 1;
+  }
+
+  // target 인덱스 찾기 위해서 이진 탐색 실행
+  while (start <= end) {
+    const mid = Math.floor((start + end) / 2);
+
+    if (nums[mid] === target) return mid;
+    if (nums[mid] < target) {
+      start = mid + 1;
+    } else {
+      end = mid - 1;
+    }
+  }
+
+  return -1;
+}

From e9d57a682f669f2373cac053d63575a81a6a1761 Mon Sep 17 00:00:00 2001
From: mmyeon <mindfulyeon@gmail.com>
Date: Sat, 15 Feb 2025 23:00:24 +0900
Subject: [PATCH 5/5] add solution : 23. Merge k Sorted Lists

---
 merge-k-sorted-lists/mmyeon.ts | 61 ++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 merge-k-sorted-lists/mmyeon.ts

diff --git a/merge-k-sorted-lists/mmyeon.ts b/merge-k-sorted-lists/mmyeon.ts
new file mode 100644
index 000000000..be4b299f9
--- /dev/null
+++ b/merge-k-sorted-lists/mmyeon.ts
@@ -0,0 +1,61 @@
+class ListNode {
+  val: number;
+  next: ListNode | null;
+  constructor(val?: number, next?: ListNode | null) {
+    this.val = val === undefined ? 0 : val;
+    this.next = next === undefined ? null : next;
+  }
+}
+
+/**
+ * @link https://leetcode.com/problems/merge-k-sorted-lists/description/
+ *
+ * 접근 방법 :
+ *  - 리스트를 배열에 넣고, 최소값을 가진 노드 찾기
+ *  - 최소값 노드를 더미 노드에 연결한 뒤 제거하고, 최소값 노드의 다음 노드를 다시 배열에 추가하기
+ *  - 배열 길이가 0이 될 때까지 반복하기
+ *
+ * 시간복잡도 : O(n * k)
+ *  - n = 총 노드의 개수
+ *  - k = 리스트의 개수
+ *  - 최소값 찾고, 최소값 제거하는 로직: O(k)
+ *  - 위의 연산을 총 n번 실행
+ *
+ * 공간복잡도 : O(k)
+ * - k = 리스트 개수
+ * - minList 배열의 크기가 최대 K개까지 유지
+ *
+ */
+
+function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
+  const minList: ListNode[] = [];
+
+  for (const list of lists) {
+    if (list !== null) minList.push(list);
+  }
+
+  const dummy = new ListNode();
+  let tail = dummy;
+
+  while (minList.length > 0) {
+    const minIndex = getMinIndex(minList);
+    const minNode = minList.splice(minIndex, 1)[0];
+
+    tail.next = minNode;
+    tail = tail.next;
+
+    if (minNode.next) minList.push(minNode.next);
+  }
+
+  return dummy.next;
+}
+
+function getMinIndex(nodes: ListNode[]): number {
+  let minIndex = 0;
+
+  for (let i = 1; i < nodes.length; i++) {
+    if (nodes[i].val < nodes[minIndex].val) minIndex = i;
+  }
+
+  return minIndex;
+}