From 1ec2d40ce3da7998d7d20e6d2639fb2a3350aa8f Mon Sep 17 00:00:00 2001 From: mmyeon Date: Mon, 24 Feb 2025 13:41:57 +0900 Subject: [PATCH 1/4] add solution : 100. Same Tree --- same-tree/mmyeon.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 same-tree/mmyeon.ts diff --git a/same-tree/mmyeon.ts b/same-tree/mmyeon.ts new file mode 100644 index 000000000..602009f29 --- /dev/null +++ b/same-tree/mmyeon.ts @@ -0,0 +1,31 @@ +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/same-tree/description/ + * + * 접근 방법 : + * - 두 노드의 값이 같을 때, 좌우 하위 트리를 재귀적으로 비교하기 + * + * 시간복잡도 : O(n) + * - n = 트리 노드 개수 + * - 모든 노드를 한 번씩 방문한다. + * + * 공간복잡도 : O(n) + * - 최악의 경우(기울어진 트리), 트리 높이만큼 재귀가 호출 된다. + */ +function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean { + if (p === null && q === null) return true; + + // false 조건 : 둘 중 하나만 null일 때, 두 노드의 값이 다른 경우 + if (p === null || q === null || p.val !== q.val) return false; + + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); +} From 203946b329b1765e73db76f6477fa607699aa595 Mon Sep 17 00:00:00 2001 From: mmyeon Date: Tue, 25 Feb 2025 10:40:26 +0900 Subject: [PATCH 2/4] add solution : 19. Remove Nth Node From End of List --- remove-nth-node-from-end-of-list/mmyeon.ts | 92 ++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 remove-nth-node-from-end-of-list/mmyeon.ts diff --git a/remove-nth-node-from-end-of-list/mmyeon.ts b/remove-nth-node-from-end-of-list/mmyeon.ts new file mode 100644 index 000000000..258213dec --- /dev/null +++ b/remove-nth-node-from-end-of-list/mmyeon.ts @@ -0,0 +1,92 @@ +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/remove-nth-node-from-end-of-list/description/ + * + * 접근 방법 : + * - 리스트 순회해서 리스트 사이즈 알아낸 뒤, 앞에서부터 몇 번째 노드를 제거해야하는지 알아내기 + * - 리스트 다시 순회해서 해당 인덱스의 노드 제거하기 + * + * 시간복잡도 : O(n) + * - n = 리스트 길이 + * - 1회 순회 -> 리스트 길이 알아내기, 추가로 1회 순회해서 노드 제거 + * + * 공간복잡도 : O(1) + * - 고정된 변수만 사용 + */ +function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null { + let listSize = 0; + let current = head; + + // 리스트 길이 구하기 + while (current) { + listSize++; + current = current.next; + } + + // 제거할 노드의 인덱스 + const targetIndex = listSize - n; + let currentIndex = 0; + + current = head; + + if (targetIndex === 0) return head ? head.next : null; + + while (current) { + if (currentIndex === targetIndex - 1 && current.next) { + current.next = current.next.next; + break; + } + currentIndex++; + current = current.next; + } + + return head; +} + +/** + * + * 접근 방법 : two pointer 사용 + * - 첫 번째 노드가 제거되는 경우가 존재하니까, dummy 노드 만들어서 헤드 노드로 설정 + * - fast 포인터의 초기 위치를 n+1로 설정하기 + * - 이후에는 slow 포인터와 fast 포인터 모두 1개씩 다음 노드로 순회 + * - fast 포인터가 끝에 도달하면, slow 포인터는 삭제할 노드 이전 노드에 도달 + * + * 시간복잡도 : O(n) + * - n = 리스트 길이 + * - 1회 순회로 삭제할 노드 알아내기 + * + * 공간복잡도 : O(1) + * - 고정된 변수만 사용 + */ +function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null { + if (head === null) return null; + + const dummy = new ListNode(); + dummy.next = head; + + let slow: ListNode | null = dummy, + fast: ListNode | null = dummy; + + // fast 포인트 위치 n+1으로 초기 세팅 + for (let i = 0; i <= n; i++) { + fast = fast.next!; + } + + while (fast !== null) { + slow = slow.next!; + fast = fast.next; + } + + // 다음 노드 삭제 + slow.next = slow.next!.next; + + return dummy.next; +} From c8d0a393236fbf8c54e77c378a2444b9691e3d72 Mon Sep 17 00:00:00 2001 From: mmyeon Date: Tue, 25 Feb 2025 14:40:12 +0900 Subject: [PATCH 3/4] add solution : Number of Connected Components in an Undirected Graph --- .../mmyeon.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 number-of-connected-components-in-an-undirected-graph/mmyeon.ts diff --git a/number-of-connected-components-in-an-undirected-graph/mmyeon.ts b/number-of-connected-components-in-an-undirected-graph/mmyeon.ts new file mode 100644 index 000000000..2790f3373 --- /dev/null +++ b/number-of-connected-components-in-an-undirected-graph/mmyeon.ts @@ -0,0 +1,50 @@ +/** + *@link https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph + * + * 접근 방법 : DFS 사용 + * - 그래프를 인접 리스트로 저장 + * - DFS 사용해서 연결된 모든 노드 방문 처리 + * -방문하지 않은 노드 발견 시 count 증가 + * + * 시간복잡도 : O(n + e) + * - n = 노드 개수, e = 엣지 개수 + * - 모든 노드 순회해서 dfs 실행 : O(n) + * - edges 순회해서 graph 생성 : O(e) + * + * 공간복잡도 : O(n + e) + * - 노드와 인접된 리스트 저장 : O(n + e) + */ + +function countComponents(n: number, edges: number[][]): number { + const graph = new Map(); + + for (let i = 0; i < n; i++) { + graph.set(i, []); + } + + for (const [node1, node2] of edges) { + graph.get(node1)!.push(node2); + graph.get(node2)!.push(node1); + } + + const visited: boolean[] = Array(n).fill(false); + + function dfs(node: number) { + // 방문한 노드 처리 + visited[node] = true; + for (const neighbor of graph.get(node) || []) { + if (!visited[neighbor]) dfs(neighbor); + } + } + + let count = 0; + for (let node = 0; node < n; node++) { + // 처음 방문하는 노드인 경우 + if (!visited[node]) { + count++; + dfs(node); + } + } + + return count; +} From 3a944260ef3ab5e851bf10f91db8f0de4c92f4dc Mon Sep 17 00:00:00 2001 From: mmyeon Date: Fri, 28 Feb 2025 22:41:21 +0900 Subject: [PATCH 4/4] add solution : 435. Non-overlapping Intervals --- non-overlapping-intervals/mmyeon.ts | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 non-overlapping-intervals/mmyeon.ts diff --git a/non-overlapping-intervals/mmyeon.ts b/non-overlapping-intervals/mmyeon.ts new file mode 100644 index 000000000..3cd6e96da --- /dev/null +++ b/non-overlapping-intervals/mmyeon.ts @@ -0,0 +1,33 @@ +/** + *@link https://leetcode.com/problems/non-overlapping-intervals/description/ + * + * 접근 방법 : + * - 최소 삭제 횟수를 구하기 위해서 인터벌 종료 시점이 빠른 걸 기준으로 정렬 + * - 탐색 범위를 좁히기 위해서 이전 인터벌 범위와 비교 -> 이전 인터벌 종료 지점보다 시작점이 빠르면 포함되어 있으면 겹치니까 삭제 카운트 증가 + * - 겹치지 않을 때는 이전 인터벌을 현재 인터벌로 업데이트하기 + * + * 시간복잡도 : O(nlogn) + * - n = intervals의 길이 + * - 정렬했으므로 O(nlogn) + * + * 공간복잡도 : O(1) + * - 고정된 변수만 사용 + */ +function eraseOverlapIntervals(intervals: number[][]): number { + intervals.sort((a, b) => a[1] - b[1]); + + let eraseCount = 0, + previousInterval = intervals[0]; + + for (let i = 1; i < intervals.length; i++) { + const currentInterval = intervals[i]; + + if (currentInterval[0] < previousInterval[1]) { + eraseCount++; + } else { + previousInterval = intervals[i]; + } + } + + return eraseCount; +}