Skip to content

Commit 5c1f5b9

Browse files
authoredOct 18, 2024··
Merge branch 'DaleStudy:main' into main
2 parents b31ef1d + 3c980d6 commit 5c1f5b9

File tree

16 files changed

+703
-0
lines changed

16 files changed

+703
-0
lines changed
 

‎course-schedule/HC-kang.ts

+34
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/flynn.go

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

‎invert-binary-tree/HC-kang.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
* https://leetcode.com/problems/invert-binary-tree
14+
* T.C. O(n)
15+
* S.C. O(n)
16+
*/
17+
function invertTree(root: TreeNode | null): TreeNode | null {
18+
if (root === null) {
19+
return null;
20+
}
21+
22+
[root.left, root.right] = [root.right, root.left];
23+
invertTree(root.left);
24+
invertTree(root.right);
25+
26+
return root;
27+
}
28+
29+
/**
30+
* T.C. O(n)
31+
* S.C. O(n)
32+
*/
33+
function invertTree(root: TreeNode | null): TreeNode | null {
34+
const stack: Array<TreeNode | null> = [root];
35+
36+
while (stack.length > 0) {
37+
const node = stack.pop()!;
38+
39+
if (node === null) {
40+
continue;
41+
}
42+
43+
[node.left, node.right] = [node.right, node.left];
44+
stack.push(node.left, node.right);
45+
}
46+
47+
return root;
48+
}

‎invert-binary-tree/flynn.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
풀이 1
3+
- 함수의 재귀호출을 이용해서 풀이할 수 있습니다
4+
5+
Big O
6+
- N: 노드의 개수
7+
- H: 트리의 높이
8+
- Time complexity: O(N)
9+
- Space complexity: O(H) (logN <= H <= N)
10+
- 재귀 호출 스택의 최대 깊이는 트리의 높이에 비례하여 증가합니다
11+
*/
12+
13+
/**
14+
* Definition for a binary tree node.
15+
* type TreeNode struct {
16+
* Val int
17+
* Left *TreeNode
18+
* Right *TreeNode
19+
* }
20+
*/
21+
func invertTree(root *TreeNode) *TreeNode {
22+
if root == nil {
23+
return root
24+
}
25+
26+
tmp := invertTree(root.Right)
27+
root.Right = invertTree(root.Left)
28+
root.Left = tmp
29+
30+
return root
31+
}
32+
33+
/*
34+
풀이 2
35+
- 큐와 반복문을 이용하여 풀이할 수 있습니다
36+
37+
Big O
38+
- N: 노드의 개수
39+
- Time complexity: O(N)
40+
- Space complexity: O(N)
41+
- 큐의 최대 크기는 N / 2 를 넘지 않습니다
42+
큐의 최대 크기는 트리의 모든 층 중에서 가장 폭이 큰 층의 노드 수와 같습니다
43+
높이가 H인 트리의 최대 폭은 1. balanced tree일 때 2. 맨 아랫 층의 폭이고 이 때의 폭 W는 2^(H-1) 입니다
44+
높이가 H인 balanced tree의 노드 개수는 2^H - 1 = N 이므로 아래 관계가 성립합니다
45+
N/2 = (2^H - 1) / 2 = 2^(H-1) - 1/2 >= 2^(H-1) = W
46+
따라서 공간 복잡도는 O(N/2) = O(N) 입니다
47+
*/
48+
49+
/**
50+
* Definition for a binary tree node.
51+
* type TreeNode struct {
52+
* Val int
53+
* Left *TreeNode
54+
* Right *TreeNode
55+
* }
56+
*/
57+
func invertTree(root *TreeNode) *TreeNode {
58+
queue := make([]*TreeNode, 0)
59+
queue = append(queue, root)
60+
61+
for len(queue) > 0 {
62+
node := queue[0]
63+
queue = queue[1:]
64+
65+
if node == nil {
66+
continue
67+
}
68+
69+
tmp := node.Left
70+
node.Left = node.Right
71+
node.Right = tmp
72+
73+
queue = append(queue, node.Left, node.Right)
74+
}
75+
76+
return root
77+
}

‎jump-game/HC-kang.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* https://leetcode.com/problems/jump-game/
3+
* T.C. O(n)
4+
* S.C. O(1)
5+
*/
6+
function canJump(nums: number[]): boolean {
7+
let max = 0;
8+
9+
for (let i = 0; i < nums.length; i++) {
10+
if (i > max) return false;
11+
max = Math.max(max, i + nums[i]);
12+
if (max >= nums.length - 1) return true;
13+
}
14+
15+
return false;
16+
}

‎jump-game/flynn.go

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
풀이 1
3+
- memo 배열을 이용하여 n-1번째 인덱스부터 0번째 인덱스 방향으로 탐색하여 풀이할 수 있습니다
4+
memo[i] = i번째 인덱스에서 출발했을 때 마지막 인덱스에 도달할 수 있는지 여부
5+
6+
Big O
7+
- N: 주어진 배열 nums의 길이
8+
- Time complexity: O(N)
9+
- Space complexity: O(N)
10+
- 풀이 2를 이용하면 O(1)으로 최적화할 수 있습니다
11+
*/
12+
13+
func canJump(nums []int) bool {
14+
n := len(nums)
15+
16+
if nums[0] == 0 && n > 1 {
17+
return false
18+
}
19+
20+
memo := make([]bool, n)
21+
memo[n-1] = true
22+
23+
for i := n - 2; i >= 0; i-- {
24+
for j := 1; j <= nums[i]; j++ {
25+
if i+j >= n {
26+
break
27+
}
28+
if memo[i+j] {
29+
memo[i] = true
30+
break
31+
}
32+
}
33+
}
34+
35+
return memo[0]
36+
}
37+
38+
/*
39+
풀이
40+
- 풀이 1을 잘 관찰하면 memo배열의 모든 값을 가지고 있을 필요가 없다는 걸 알 수 있습니다
41+
memo 배열 대신에, 문제의 조건대로 마지막 인덱스까지 갈 수 있는 가장 좌측의 인덱스만 기록합니다 (leftmost)
42+
43+
Big O
44+
- N: 주어진 배열 nums의 길이
45+
- Time complexity: O(N)
46+
- Space complexity: O(1)
47+
*/
48+
49+
func canJump(nums []int) bool {
50+
n := len(nums)
51+
52+
if nums[0] == 0 && n > 1 {
53+
return false
54+
}
55+
56+
leftmost := n - 1
57+
58+
for i := n - 2; i >= 0; i-- {
59+
if i+nums[i] >= leftmost {
60+
leftmost = i
61+
}
62+
}
63+
64+
return leftmost == 0
65+
}

‎linked-list-cycle/hwanmini.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// 시간복잡도: O(n)
2+
// 공간복잡도: O(1)
3+
4+
/**
5+
* Definition for singly-linked list.
6+
* function ListNode(val) {
7+
* this.val = val;
8+
* this.next = null;
9+
* }
10+
*/
11+
12+
/**
13+
* @param {ListNode} head
14+
* @return {boolean}
15+
*/
16+
var hasCycle = function(head) {
17+
let fastPointer = head;
18+
let slowPointer = head;
19+
20+
while (fastPointer && fastPointer.next) {
21+
slowPointer = slowPointer.next;
22+
fastPointer = fastPointer.next.next
23+
24+
if (fastPointer === slowPointer) return true
25+
26+
}
27+
28+
return false
29+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
TC: O(n)
3+
SC: O(n)
4+
"""
5+
class Solution:
6+
def lengthOfLongestSubstring(self, s: str) -> int:
7+
str_list = []
8+
max_length = 0
9+
for i in range(len(s)):
10+
if s[i] not in str_list:
11+
str_list.append(s[i])
12+
else:
13+
if max_length < len(str_list):
14+
max_length = len(str_list)
15+
str_list = str_list[str_list.index(s[i])+1:]
16+
str_list.append(s[i])
17+
18+
if max_length < len(str_list):
19+
max_length = len(str_list)
20+
21+
return max_length
22+

0 commit comments

Comments
 (0)
Please sign in to comment.