-
-
Notifications
You must be signed in to change notification settings - Fork 245
[EGON] Week12 Solutions #569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
f5ba907
feat: solve #228 with python
EgonD3V 095786f
feat: solve #248 with python
EgonD3V 68baacf
feat: solve #263 with python
EgonD3V e4e23ac
feat: solve #278 with python
EgonD3V 54fcb0f
feat: solve #288 with python
EgonD3V cfbb952
chore: edit #263 comment
EgonD3V File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def merge(self, intervals: List[List[int]]) -> List[List[int]]: | ||
return self.solve_stack(intervals) | ||
|
||
""" | ||
Runtime: 8 ms (Beats 49.77%) | ||
Time Complexity: | ||
- intervals의 길이를 n이라 하면, intervals를 시작 지점을 기준으로 정렬하는데 O(n log n) | ||
- intervals를 조회하면서 연산하는데, 내부 연산은 모두 O(1)이므로 O(n) | ||
> O(n log n) + O(n) ~= O(n log n) | ||
|
||
Memory: 19.88 MB (Beats: 99.31%) | ||
Space Complexity: O(n) | ||
- intervals는 내부 정렬만 했으므로 추가 메모리 사용 메모리 없음 | ||
- 겹치는 구간이 없는 최악의 경우 merged의 크기는 intervals의 크기와 같아지므로, O(n) upper bound | ||
""" | ||
|
||
def solve_stack(self, intervals: List[List[int]]) -> List[List[int]]: | ||
intervals.sort() | ||
|
||
merged = [] | ||
for interval in intervals: | ||
if not merged: | ||
merged.append(interval) | ||
continue | ||
|
||
new_start, new_end = interval | ||
_, last_end = merged[-1] | ||
if last_end < new_start: | ||
merged.append(interval) | ||
else: | ||
merged[-1][1] = max(last_end, new_end) | ||
|
||
return merged | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
|
||
def test_1(self): | ||
intervals = [[1, 3], [2, 6], [8, 10], [15, 18]] | ||
output = [[1, 6], [8, 10], [15, 18]] | ||
|
||
self.assertEqual(Solution().merge(intervals), output) | ||
|
||
def test_2(self): | ||
intervals = [[1, 4], [4, 5]] | ||
output = [[1, 5]] | ||
|
||
self.assertEqual(Solution().merge(intervals), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
77 changes: 77 additions & 0 deletions
77
number-of-connected-components-in-an-undirected-graph/EGON.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class ListNode: | ||
def __init__(self, val=0, next=None): | ||
self.val = val | ||
self.next = next | ||
|
||
|
||
class Solution: | ||
def countComponents(self, n: int, edges: List[List[int]]) -> int: | ||
return self.solve_union_find(n, edges) | ||
|
||
""" | ||
LintCode 로그인이 안되어서 https://neetcode.io/problems/count-connected-components에서 실행시키고 통과만 확인했습니다. | ||
|
||
Runtime: ? ms (Beats ?%) | ||
Time Complexity: O(max(m, n)) | ||
- UnionFind의 parent 생성에 O(n) | ||
- edges 조회에 O(m) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 맥락상 |
||
- Union-find 알고리즘의 union을 매 조회마다 사용하므로, * O(α(n)) (α는 아커만 함수의 역함수) | ||
- UnionFind의 각 노드의 부모를 찾기 위해, n번 find에 O(n * α(n)) | ||
> O(n) + O(m * α(n)) + O(n * α(n)) ~= O(max(m, n) * α(n)) ~= O(max(m, n)) (∵ α(n) ~= C) | ||
|
||
Memory: ? MB (Beats ?%) | ||
Space Complexity: O(n) | ||
- UnionFind의 parent와 rank가 크기가 n인 리스트이므로, O(n) + O(n) | ||
> O(n) + O(n) ~= O(n) | ||
""" | ||
|
||
def solve_union_find(self, n: int, edges: List[List[int]]) -> int: | ||
|
||
class UnionFind: | ||
def __init__(self, size: int): | ||
self.parent = [i for i in range(size)] | ||
self.rank = [1] * size | ||
|
||
def union(self, first: int, second: int): | ||
first_parent, second_parent = self.find(first), self.find(second) | ||
|
||
if self.rank[first_parent] > self.rank[second_parent]: | ||
self.parent[second_parent] = first_parent | ||
elif self.rank[first_parent] < self.rank[second_parent]: | ||
self.parent[first_parent] = second_parent | ||
else: | ||
self.parent[second_parent] = first_parent | ||
self.rank[first_parent] += 1 | ||
|
||
def find(self, node: int): | ||
if self.parent[node] != node: | ||
self.parent[node] = self.find(self.parent[node]) | ||
|
||
return self.parent[node] | ||
|
||
union_find = UnionFind(size=n) | ||
for first, second in edges: | ||
union_find.union(first, second) | ||
|
||
result = set() | ||
for i in range(n): | ||
result.add(union_find.find(i)) | ||
|
||
return len(result) | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
n = 5 | ||
edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]] | ||
output = False | ||
|
||
self.assertEqual(Solution().countComponents(n, edges), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
from typing import Optional | ||
from unittest import TestCase, main | ||
|
||
|
||
# Definition for singly-linked list. | ||
class ListNode: | ||
def __init__(self, val=0, next=None): | ||
self.val = val | ||
self.next = next | ||
|
||
def values(self) -> [int]: | ||
result = [] | ||
node = self | ||
while node: | ||
result.append(node.val) | ||
node = node.next | ||
|
||
return result | ||
|
||
|
||
class Solution: | ||
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: | ||
return self.solve_two_pointer(head, n) | ||
""" | ||
Runtime: 0 ms (Beats 100.00%) | ||
Time Complexity: O(n) | ||
> list의 모든 node + dummy node를 탐색하므로 O(n + 1) ~= O(n) | ||
|
||
Memory: 16.62 MB (Beats 15.78%) | ||
Space Complexity: O(1) | ||
> 포인터만 사용하므로 O(1) | ||
""" | ||
def solve_two_pointer(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: | ||
if head.next is None: | ||
return None | ||
|
||
dummy = ListNode(-1) | ||
dummy.next = head | ||
head = dummy | ||
|
||
slow = fast = head | ||
while n: | ||
if fast.next: | ||
fast = fast.next | ||
n -= 1 | ||
|
||
while fast is not None: | ||
if fast.next is None: | ||
slow.next = slow.next.next | ||
break | ||
else: | ||
slow = slow.next | ||
fast = fast.next | ||
|
||
return head.next | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
node_1 = ListNode(1) | ||
node_2 = ListNode(2) | ||
node_3 = ListNode(3) | ||
node_4 = ListNode(4) | ||
node_5 = ListNode(5) | ||
|
||
node_1.next = node_2 | ||
node_2.next = node_3 | ||
node_3.next = node_4 | ||
node_4.next = node_5 | ||
|
||
n = 2 | ||
output = [1, 2, 3, 5] | ||
self.assertEqual(Solution().removeNthFromEnd(node_1, n).values(), output) | ||
|
||
def test_2(self): | ||
node_1 = ListNode(1) | ||
n = 1 | ||
output = [] | ||
self.assertEqual(Solution().removeNthFromEnd(node_1, n).values(), output) | ||
|
||
def test_3(self): | ||
node_1 = ListNode(1) | ||
node_2 = ListNode(2) | ||
node_1.next = node_2 | ||
n = 2 | ||
output = [2] | ||
self.assertEqual(Solution().removeNthFromEnd(node_1, n).values(), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from typing import Optional | ||
from unittest import TestCase, main | ||
|
||
|
||
# Definition for a binary tree node. | ||
class TreeNode: | ||
def __init__(self, val=0, left=None, right=None): | ||
self.val = val | ||
self.left = left | ||
self.right = right | ||
|
||
|
||
class Solution: | ||
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: | ||
return self.solve_dfs(p, q) | ||
|
||
""" | ||
Runtime: 0 ms (Beats 100.00%) | ||
Time Complexity: O(min(p, q)) | ||
> dfs를 통해 모든 node를 방문하므로, 각 트리의 node의 갯수를 각각 p, q라 하면, O(min(p, q)) | ||
|
||
Memory: 16.62 MB (Beats 15.78%) | ||
Space Complexity: O(min(p, q)) | ||
> 일반적인 경우 트리의 깊이만큼 dfs 호출 스택이 쌓이나, 최악의 경우 한쪽으로 편향되었다면 O(min(p, q)), upper bound | ||
""" | ||
def solve_dfs(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: | ||
|
||
def dfs(p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: | ||
if p is None and q is None: | ||
return True | ||
elif (p is not None and q is not None) and (p.val == q.val): | ||
return dfs(p.left, q.left) and dfs(p.right, q.right) | ||
else: | ||
return False | ||
|
||
return dfs(p, q) | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
p_1 = TreeNode(1) | ||
p_2 = TreeNode(2) | ||
p_3 = TreeNode(3) | ||
p_1.left = p_2 | ||
p_1.right = p_3 | ||
|
||
q_1 = TreeNode(1) | ||
q_2 = TreeNode(3) | ||
q_3 = TreeNode(3) | ||
q_1.left = q_2 | ||
q_1.right = q_3 | ||
|
||
self.assertEqual(Solution().isSameTree(p_1, q_1), True) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from typing import Optional | ||
|
||
|
||
# Definition for a binary tree node. | ||
class TreeNode: | ||
def __init__(self, val=0, left=None, right=None): | ||
self.val = val | ||
self.left = left | ||
self.right = right | ||
|
||
|
||
class Codec: | ||
""" | ||
Runtime: 76 ms (Beats 85.72%) | ||
Time Complexity: O(n) | ||
> dfs를 통해 모든 node를 방문하므로, O(n) | ||
|
||
Memory: 21.40 MB (Beats 12.82%) | ||
Space Complexity: O(n) | ||
> 일반적인 경우 트리의 깊이만큼 dfs 호출 스택이 쌓이나, 최악의 경우 한쪽으로 편향되었다면 트리의 깊이가 n이 될 수 있으므로 O(n), upper bound | ||
""" | ||
|
||
def serialize(self, root): | ||
"""Encodes a tree to a single string. | ||
|
||
:type root: TreeNode | ||
:rtype: str | ||
""" | ||
|
||
def dfs(node: Optional[TreeNode]) -> None: | ||
if node is None: | ||
result.append("null") | ||
return | ||
result.append(str(node.val)) | ||
dfs(node.left) | ||
dfs(node.right) | ||
|
||
result = [] | ||
dfs(root) | ||
return ','.join(result) | ||
|
||
def deserialize(self, data): | ||
"""Decodes your encoded data to tree. | ||
|
||
:type data: str | ||
:rtype: TreeNode | ||
""" | ||
|
||
def dfs() -> Optional[TreeNode]: | ||
val = next(values) | ||
if val == "null": | ||
return None | ||
node = TreeNode(int(val)) | ||
node.left = dfs() | ||
node.right = dfs() | ||
return node | ||
|
||
values = iter(data.split(',')) | ||
return dfs() | ||
|
||
|
||
# Your Codec object will be instantiated and called as such: | ||
# ser = Codec() | ||
# deser = Codec() | ||
# ans = deser.deserialize(ser.serialize(root)) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.