diff --git a/merge-intervals/flynn.go b/merge-intervals/flynn.go new file mode 100644 index 000000000..ba53f55b1 --- /dev/null +++ b/merge-intervals/flynn.go @@ -0,0 +1,41 @@ +/* +Big O +- N: 주어진 배열 intervals의 길이 +- Time complexity: O(NlogN) + - intervals를 start의 오름차순으로 정렬 -> O(NlogN) + - 반복문 -> O(N) + - O(NlogN + N) = O(NlogN) +- Space complexity: O(N) + - 정답 배열의 크기 -> O(N) +*/ + +import "sort" + +func merge(intervals [][]int) [][]int { + sort.Slice(intervals, func(i, j int) bool { + return intervals[i][0] < intervals[j][0] + }) + res := make([][]int, 0) + start := intervals[0][0] + end := intervals[0][1] + for i := 1; i < len(intervals); i++ { + curr := intervals[i] + if end >= curr[0] { + end = max(end, curr[1]) + } else { + res = append(res, []int{start, end}) + start = curr[0] + end = curr[1] + } + } + res = append(res, []int{start, end}) + return res +} + +func max(a, b int) int { + if a > b { + return a + } else { + return b + } +} diff --git a/number-of-connected-components-in-an-undirected-graph/flynn.go b/number-of-connected-components-in-an-undirected-graph/flynn.go new file mode 100644 index 000000000..a85c4ec0e --- /dev/null +++ b/number-of-connected-components-in-an-undirected-graph/flynn.go @@ -0,0 +1,47 @@ +/* +풀이 +- DFS와 hashmap(set)을 이용하여 풀이할 수 있습니다 +- 이전에 풀이했던 course schedule 문제와 유사합니다 +Big O +- N: 노드 개수 +- E: 간선의 개수 +- Time complexity: O(N + E) + - adj를 생성하는 반복문의 시간복잡도는 E에 비례하여 증가합니다 + - 전체 노드를 최대 1번씩 조회하므로 두번째 반복문의 시간복잡도는 N에 비례하여 증가합니다 +- Space complexity: O(N + E) + - adjacency list의 크기는 E에 비례하여 증가합니다 + - checked의 크기는 N에 비례하여 증가합니다 + - check 함수의 재귀 호출 스택 깊이 또한 최악의 경우, N에 비례하여 증가합니다 +*/ + +func countComponents(n int, edges [][]int) int { + adj := make(map[int][]int) + for _, edge := range edges { + adj[edge[0]] = append(adj[edge[0]], edge[1]) + adj[edge[1]] = append(adj[edge[1]], edge[0]) + } + // Go는 {int: bool} hashmap을 set처럼 사용함 + checked := make(map[int]bool) // 모든 탐색이 끝난 노드를 기록함 + // 각 node를 조회하는 함수 + var check func(int) + check = func(i int) { + checked[i] = true + for _, nxt := range adj[i] { + if _, ok := checked[nxt]; ok { + continue + } + check(nxt) + } + } + + res := 0 + for i := 0; i < n; i++ { + if _, ok := checked[i]; ok { + continue + } + res++ + check(i) + } + + return res +} diff --git a/remove-nth-node-from-end-of-list/flynn.go b/remove-nth-node-from-end-of-list/flynn.go new file mode 100644 index 000000000..6ba8a2d1e --- /dev/null +++ b/remove-nth-node-from-end-of-list/flynn.go @@ -0,0 +1,34 @@ +/* +풀이 +- n+1 간격을 유지하며 이동하는 두 개의 포인터를 이용하면 one-pass로 해결할 수 있습니다 +Big O +- M: 링크드리스트의 길이 +- Time complexity: O(M) +- Space complexity: O(1) +*/ + +/** + * Definition for singly-linked list. + * type ListNode struct { + * Val int + * Next *ListNode + * } + */ + + func removeNthFromEnd(head *ListNode, n int) *ListNode { + dummy := &ListNode{Next: head} + + slow := dummy + fast := dummy + for i := 0; i < n+1; i++ { + fast = fast.Next + } + + for fast != nil { + slow = slow.Next + fast = fast.Next + } + slow.Next = slow.Next.Next + + return dummy.Next +} diff --git a/same-tree/flynn.go b/same-tree/flynn.go new file mode 100644 index 000000000..bea6a929b --- /dev/null +++ b/same-tree/flynn.go @@ -0,0 +1,38 @@ +/* +풀이 +- 재귀함수를 이용해서 풀이할 수 있습니다 +Big O +- N: 트리 노드의 개수 +- H: 트리의 높이 (logN <= H <= N) +- Time complexity: O(N) + - 모든 노드를 최대 1번 탐색합니다 +- Space complexity: O(H) + - 재귀 호출 스택의 깊이는 H에 비례하여 증가합니다 +*/ + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + func isSameTree(p *TreeNode, q *TreeNode) bool { + // base case + if p == nil && q == nil { + return true + } else if p == nil || q == nil { + return false + } + + if p.Val != q.Val { + return false + } + + if !isSameTree(p.Left, q.Left) || !isSameTree(p.Right, q.Right) { + return false + } + + return true +} diff --git a/serialize-and-deserialize-binary-tree/flynn.go b/serialize-and-deserialize-binary-tree/flynn.go new file mode 100644 index 000000000..e3b8ba2aa --- /dev/null +++ b/serialize-and-deserialize-binary-tree/flynn.go @@ -0,0 +1,98 @@ +/* +풀이 +- DFS를 이용하여 풀이합니다 +Big O +- N: 노드의 수 +- Serialize + - Time complexity: O(N) + - 모든 노드를 최대 1번 조회합니다 + - Space complexity: O(N) + - buildString의 재귀 호출 스택의 깊이는 노드의 높이에 비례하여 증가하며, 노드의 높이는 최대 N입니다 + - 결과 string의 크기 또한 N에 비례하는 형태로 증가합니다 +- Deserialize + - Time complexity: O(N) + - 모든 노드를 최대 1번 조회합니다 + - Space complexity: O(N) + - data를 split한 배열의 크기가 N에 비례하여 증가합니다 + - buildTree의 재귀 호출 스택의 깊이는 노드의 높이에 비례하여 증가하며, 노드의 높이는 최대 N입니다 +*/ + +import ( + "strconv" + "strings" +) + +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +const ( + DELIMITER = "|" +) + +type Codec struct { +} + +func Constructor() Codec { + codec := Codec{} + return codec +} + +// Serializes a tree to a single string. +func (this *Codec) serialize(root *TreeNode) string { + if root == nil { + return "" + } + var sb strings.Builder + buildString(&sb, root) + return sb.String() +} + +// Deserializes your encoded data to tree. +func (this *Codec) deserialize(data string) *TreeNode { + if data == "" { + return nil + } + splitData := make([]string, 0, len(data)/2) + splitData = strings.Split(data, DELIMITER) + splitData = splitData[:len(splitData)-1] + return buildTree(&splitData) +} + +// ----- Helpers ----- +func buildString(sb *strings.Builder, node *TreeNode) { + if node == nil { + sb.WriteString(DELIMITER) + return + } + sb.WriteString(strconv.Itoa(node.Val)) + sb.WriteString(DELIMITER) + buildString(sb, node.Left) + buildString(sb, node.Right) +} + +func buildTree(splitData *[]string) *TreeNode { + val := (*splitData)[0] + *splitData = (*splitData)[1:] + if val == "" { + return nil + } + node := &TreeNode{} + intVal, _ := strconv.Atoi(val) + node.Val = intVal + node.Left = buildTree(splitData) + node.Right = buildTree(splitData) + return node +} + +/** + * Your Codec object will be instantiated and called as such: + * ser := Constructor(); + * deser := Constructor(); + * data := ser.serialize(root); + * ans := deser.deserialize(data); + */