Skip to content

Commit 648f6b2

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 1f50aa2 + 849ece4 commit 648f6b2

File tree

14 files changed

+707
-0
lines changed

14 files changed

+707
-0
lines changed

merge-intervals/EGON.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class Solution:
6+
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
7+
return self.solve_stack(intervals)
8+
9+
"""
10+
Runtime: 8 ms (Beats 49.77%)
11+
Time Complexity:
12+
- intervals의 길이를 n이라 하면, intervals를 시작 지점을 기준으로 정렬하는데 O(n log n)
13+
- intervals를 조회하면서 연산하는데, 내부 연산은 모두 O(1)이므로 O(n)
14+
> O(n log n) + O(n) ~= O(n log n)
15+
16+
Memory: 19.88 MB (Beats: 99.31%)
17+
Space Complexity: O(n)
18+
- intervals는 내부 정렬만 했으므로 추가 메모리 사용 메모리 없음
19+
- 겹치는 구간이 없는 최악의 경우 merged의 크기는 intervals의 크기와 같아지므로, O(n) upper bound
20+
"""
21+
22+
def solve_stack(self, intervals: List[List[int]]) -> List[List[int]]:
23+
intervals.sort()
24+
25+
merged = []
26+
for interval in intervals:
27+
if not merged:
28+
merged.append(interval)
29+
continue
30+
31+
new_start, new_end = interval
32+
_, last_end = merged[-1]
33+
if last_end < new_start:
34+
merged.append(interval)
35+
else:
36+
merged[-1][1] = max(last_end, new_end)
37+
38+
return merged
39+
40+
41+
class _LeetCodeTestCases(TestCase):
42+
43+
def test_1(self):
44+
intervals = [[1, 3], [2, 6], [8, 10], [15, 18]]
45+
output = [[1, 6], [8, 10], [15, 18]]
46+
47+
self.assertEqual(Solution().merge(intervals), output)
48+
49+
def test_2(self):
50+
intervals = [[1, 4], [4, 5]]
51+
output = [[1, 5]]
52+
53+
self.assertEqual(Solution().merge(intervals), output)
54+
55+
56+
if __name__ == '__main__':
57+
main()

merge-intervals/TonyKim9401.java

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// TC: O(n log n)
2+
// It takes n log n to sort array, visit all elements in O(n) time, total O(n log n)
3+
// SC: O(n)
4+
// Needs max O(n) space to save intervals
5+
class Solution {
6+
public int[][] merge(int[][] intervals) {
7+
int n = intervals.length;
8+
if (n == 1) return intervals;
9+
10+
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
11+
List<int[]> output = new ArrayList<>();
12+
output.add(intervals[0]);
13+
14+
int[] currentInterval = intervals[0];
15+
16+
for (int[] interval : intervals) {
17+
int currentEnd = currentInterval[1];
18+
int nextStart = interval[0];
19+
int nextEnd = interval[1];
20+
if (currentEnd >= nextStart) {
21+
currentInterval[1] = Math.max(currentEnd, nextEnd);
22+
} else {
23+
currentInterval = interval;
24+
output.add(currentInterval);
25+
}
26+
}
27+
28+
return output.toArray(new int[output.size()][]);
29+
}
30+
}

merge-intervals/flynn.go

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Big O
3+
- N: 주어진 배열 intervals의 길이
4+
- Time complexity: O(NlogN)
5+
- intervals를 start의 오름차순으로 정렬 -> O(NlogN)
6+
- 반복문 -> O(N)
7+
- O(NlogN + N) = O(NlogN)
8+
- Space complexity: O(N)
9+
- 정답 배열의 크기 -> O(N)
10+
*/
11+
12+
import "sort"
13+
14+
func merge(intervals [][]int) [][]int {
15+
sort.Slice(intervals, func(i, j int) bool {
16+
return intervals[i][0] < intervals[j][0]
17+
})
18+
res := make([][]int, 0)
19+
start := intervals[0][0]
20+
end := intervals[0][1]
21+
for i := 1; i < len(intervals); i++ {
22+
curr := intervals[i]
23+
if end >= curr[0] {
24+
end = max(end, curr[1])
25+
} else {
26+
res = append(res, []int{start, end})
27+
start = curr[0]
28+
end = curr[1]
29+
}
30+
}
31+
res = append(res, []int{start, end})
32+
return res
33+
}
34+
35+
func max(a, b int) int {
36+
if a > b {
37+
return a
38+
} else {
39+
return b
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class ListNode:
6+
def __init__(self, val=0, next=None):
7+
self.val = val
8+
self.next = next
9+
10+
11+
class Solution:
12+
def countComponents(self, n: int, edges: List[List[int]]) -> int:
13+
return self.solve_union_find(n, edges)
14+
15+
"""
16+
LintCode 로그인이 안되어서 https://neetcode.io/problems/count-connected-components에서 실행시키고 통과만 확인했습니다.
17+
18+
Runtime: ? ms (Beats ?%)
19+
Time Complexity: O(max(m, n))
20+
- UnionFind의 parent 생성에 O(n)
21+
- edges 조회에 O(m)
22+
- Union-find 알고리즘의 union을 매 조회마다 사용하므로, * O(α(n)) (α는 아커만 함수의 역함수)
23+
- UnionFind의 각 노드의 부모를 찾기 위해, n번 find에 O(n * α(n))
24+
> O(n) + O(m * α(n)) + O(n * α(n)) ~= O(max(m, n) * α(n)) ~= O(max(m, n)) (∵ α(n) ~= C)
25+
26+
Memory: ? MB (Beats ?%)
27+
Space Complexity: O(n)
28+
- UnionFind의 parent와 rank가 크기가 n인 리스트이므로, O(n) + O(n)
29+
> O(n) + O(n) ~= O(n)
30+
"""
31+
32+
def solve_union_find(self, n: int, edges: List[List[int]]) -> int:
33+
34+
class UnionFind:
35+
def __init__(self, size: int):
36+
self.parent = [i for i in range(size)]
37+
self.rank = [1] * size
38+
39+
def union(self, first: int, second: int):
40+
first_parent, second_parent = self.find(first), self.find(second)
41+
42+
if self.rank[first_parent] > self.rank[second_parent]:
43+
self.parent[second_parent] = first_parent
44+
elif self.rank[first_parent] < self.rank[second_parent]:
45+
self.parent[first_parent] = second_parent
46+
else:
47+
self.parent[second_parent] = first_parent
48+
self.rank[first_parent] += 1
49+
50+
def find(self, node: int):
51+
if self.parent[node] != node:
52+
self.parent[node] = self.find(self.parent[node])
53+
54+
return self.parent[node]
55+
56+
union_find = UnionFind(size=n)
57+
for first, second in edges:
58+
union_find.union(first, second)
59+
60+
result = set()
61+
for i in range(n):
62+
result.add(union_find.find(i))
63+
64+
return len(result)
65+
66+
67+
class _LeetCodeTestCases(TestCase):
68+
def test_1(self):
69+
n = 5
70+
edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]]
71+
output = False
72+
73+
self.assertEqual(Solution().countComponents(n, edges), output)
74+
75+
76+
if __name__ == '__main__':
77+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// TC: O(n + m)
2+
// n = the number of nodes, m = the number of edges
3+
// SC: O(n + m)
4+
// n, m are the each size of the 2 demension array 'edges'
5+
public class Solution {
6+
public int countComponents(int n, int[][] edges) {
7+
List<List<Integer>> graph = new ArrayList<>();
8+
9+
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
10+
11+
for (int[] edge : edges) {
12+
graph.get(edge[0]).add(edge[1]);
13+
graph.get(edge[1]).add(edge[0]);
14+
}
15+
16+
boolean[] visit = new boolean[n];
17+
int count = 0;
18+
19+
for (int i = 0; i < n; i++) {
20+
if (!visit[i]) {
21+
count += 1;
22+
dfs(i, graph, visit);
23+
}
24+
}
25+
return count;
26+
}
27+
28+
private void dfs(int node, List<List<Integer>> graph, boolean[] visit) {
29+
visit[node] = true;
30+
for (int neighbor : graph.get(node)) {
31+
if (!visit[neighbor]) dfs(neighbor, graph, visit);
32+
}
33+
}
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
풀이
3+
- DFS와 hashmap(set)을 이용하여 풀이할 수 있습니다
4+
- 이전에 풀이했던 course schedule 문제와 유사합니다
5+
Big O
6+
- N: 노드 개수
7+
- E: 간선의 개수
8+
- Time complexity: O(N + E)
9+
- adj를 생성하는 반복문의 시간복잡도는 E에 비례하여 증가합니다
10+
- 전체 노드를 최대 1번씩 조회하므로 두번째 반복문의 시간복잡도는 N에 비례하여 증가합니다
11+
- Space complexity: O(N + E)
12+
- adjacency list의 크기는 E에 비례하여 증가합니다
13+
- checked의 크기는 N에 비례하여 증가합니다
14+
- check 함수의 재귀 호출 스택 깊이 또한 최악의 경우, N에 비례하여 증가합니다
15+
*/
16+
17+
func countComponents(n int, edges [][]int) int {
18+
adj := make(map[int][]int)
19+
for _, edge := range edges {
20+
adj[edge[0]] = append(adj[edge[0]], edge[1])
21+
adj[edge[1]] = append(adj[edge[1]], edge[0])
22+
}
23+
// Go는 {int: bool} hashmap을 set처럼 사용함
24+
checked := make(map[int]bool) // 모든 탐색이 끝난 노드를 기록함
25+
// 각 node를 조회하는 함수
26+
var check func(int)
27+
check = func(i int) {
28+
checked[i] = true
29+
for _, nxt := range adj[i] {
30+
if _, ok := checked[nxt]; ok {
31+
continue
32+
}
33+
check(nxt)
34+
}
35+
}
36+
37+
res := 0
38+
for i := 0; i < n; i++ {
39+
if _, ok := checked[i]; ok {
40+
continue
41+
}
42+
res++
43+
check(i)
44+
}
45+
46+
return res
47+
}
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
from typing import Optional
2+
from unittest import TestCase, main
3+
4+
5+
# Definition for singly-linked list.
6+
class ListNode:
7+
def __init__(self, val=0, next=None):
8+
self.val = val
9+
self.next = next
10+
11+
def values(self) -> [int]:
12+
result = []
13+
node = self
14+
while node:
15+
result.append(node.val)
16+
node = node.next
17+
18+
return result
19+
20+
21+
class Solution:
22+
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
23+
return self.solve_two_pointer(head, n)
24+
"""
25+
Runtime: 0 ms (Beats 100.00%)
26+
Time Complexity: O(n)
27+
> list의 모든 node + dummy node를 탐색하므로 O(n + 1) ~= O(n)
28+
29+
Memory: 16.62 MB (Beats 15.78%)
30+
Space Complexity: O(1)
31+
> 포인터만 사용하므로 O(1)
32+
"""
33+
def solve_two_pointer(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
34+
if head.next is None:
35+
return None
36+
37+
dummy = ListNode(-1)
38+
dummy.next = head
39+
head = dummy
40+
41+
slow = fast = head
42+
while n:
43+
if fast.next:
44+
fast = fast.next
45+
n -= 1
46+
47+
while fast is not None:
48+
if fast.next is None:
49+
slow.next = slow.next.next
50+
break
51+
else:
52+
slow = slow.next
53+
fast = fast.next
54+
55+
return head.next
56+
57+
58+
class _LeetCodeTestCases(TestCase):
59+
def test_1(self):
60+
node_1 = ListNode(1)
61+
node_2 = ListNode(2)
62+
node_3 = ListNode(3)
63+
node_4 = ListNode(4)
64+
node_5 = ListNode(5)
65+
66+
node_1.next = node_2
67+
node_2.next = node_3
68+
node_3.next = node_4
69+
node_4.next = node_5
70+
71+
n = 2
72+
output = [1, 2, 3, 5]
73+
self.assertEqual(Solution().removeNthFromEnd(node_1, n).values(), output)
74+
75+
def test_2(self):
76+
node_1 = ListNode(1)
77+
n = 1
78+
output = []
79+
self.assertEqual(Solution().removeNthFromEnd(node_1, n).values(), output)
80+
81+
def test_3(self):
82+
node_1 = ListNode(1)
83+
node_2 = ListNode(2)
84+
node_1.next = node_2
85+
n = 2
86+
output = [2]
87+
self.assertEqual(Solution().removeNthFromEnd(node_1, n).values(), output)
88+
89+
90+
if __name__ == '__main__':
91+
main()

0 commit comments

Comments
 (0)