-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #542 from lymchgmk/feat/week10
[EGON] Week10 Solutions
- Loading branch information
Showing
5 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,58 @@ | ||
from collections import deque | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: | ||
return self.solve_topological_sort(numCourses, prerequisites) | ||
|
||
""" | ||
Runtime: 1 ms (Beats 100.00%) | ||
Time Complexity: o(c + p) | ||
- graph 및 rank 갱신에 prerequisites의 길이 p만큼 조회하는데 O(p) | ||
- queue의 초기 노드 삽입에 numCourses만큼 조회하는데 O(c) | ||
- queue에서 위상 정렬로 탐색하는데 모든 노드와 간선을 조회하는데 O(c + p) | ||
> O(p) + O(c) + O(c + p) ~= o(c + p) | ||
Memory: 17.85 MB (Beats 99.94%) | ||
Space Complexity: O(c) | ||
- graph 변수 사용에 O(c + p) | ||
- rank 변수 사용에 O(c) | ||
- queue 변수 사용에서 최대 크기는 graph의 크기와 같으므로 O(c) | ||
> O(c + p) + O(c) + O(c) ~= O(c + p) | ||
""" | ||
def solve_topological_sort(self, numCourses: int, prerequisites: List[List[int]]) -> bool: | ||
graph = {i: [] for i in range(numCourses)} | ||
rank = [0] * numCourses | ||
for u, v in prerequisites: | ||
graph[v].append(u) | ||
rank[u] += 1 | ||
|
||
queue = deque() | ||
for i in range(numCourses): | ||
if rank[i] == 0: | ||
queue.append(i) | ||
|
||
count = 0 | ||
while queue: | ||
node = queue.popleft() | ||
count += 1 | ||
for neighbor in graph[node]: | ||
rank[neighbor] -= 1 | ||
if rank[neighbor] == 0: | ||
queue.append(neighbor) | ||
|
||
return count == numCourses | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
numCourses = 5 | ||
prerequisites = [[1,4],[2,4],[3,1],[3,2]] | ||
output = True | ||
self.assertEqual(Solution.canFinish(Solution(), numCourses, prerequisites), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains 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,48 @@ | ||
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 invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: | ||
return self.solve_dfs(root) | ||
|
||
""" | ||
Runtime: 0 ms (Beats 100.00%) | ||
Time Complexity: O(n) | ||
> 트리의 모든 node를 방문하므로 O(n) | ||
Memory: 16.53 MB (Beats 25.95%) | ||
Space Complexity: O(n) | ||
> stack의 최대 크기는 트리의 최장 경로를 이루는 node의 갯수이고, 최악의 경우 트리의 한 쪽으로 모든 node가 이어져있는 경우이므로 O(n), upper bound | ||
""" | ||
def solve_dfs(self, root: Optional[TreeNode]) -> Optional[TreeNode]: | ||
if root is None: | ||
return root | ||
|
||
stack = [root] | ||
while stack: | ||
curr_node = stack.pop() | ||
curr_node.left, curr_node.right = curr_node.right, curr_node.left | ||
if curr_node.left: | ||
stack.append(curr_node.left) | ||
if curr_node.right: | ||
stack.append(curr_node.right) | ||
|
||
return root | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
return | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains 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,43 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def canJump(self, nums: List[int]) -> bool: | ||
return self.solve_dp(nums) | ||
|
||
""" | ||
Runtime: 3130 ms (Beats 11.42%) | ||
Time Complexity: O(n * m) | ||
- dp 배열 생성에 nums의 길이 n 만큼 조회하는데 O(n) | ||
- 생성한 dp 배열을 조회하는데 O(n) | ||
- dp[i]에서 점프하는 범위에 의해 * O(2 * m) | ||
> O(n) + O(n) * O(2 * m) ~= O(n * m) | ||
Memory: 17.80 MB (Beats 72.54%) | ||
Space Complexity: O(n) | ||
> nums의 길이에 비례하는 dp 배열 하나만 사용, O(n) | ||
""" | ||
def solve_dp(self, nums: List[int]) -> bool: | ||
dp = [True if i == 0 else False for i in range(len(nums))] | ||
for i in range(len(nums)): | ||
if dp[-1] is True: | ||
return True | ||
|
||
if dp[i] is True: | ||
for jump in range(nums[i] + 1): | ||
if 0 <= i + jump < len(dp): | ||
dp[i + jump] = True | ||
|
||
return dp[-1] | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
nums = [2, 3, 1, 1, 4] | ||
output = True | ||
self.assertEqual(Solution.canJump(Solution(), nums), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains 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,55 @@ | ||
from heapq import heappush, heappop | ||
from typing import List, Optional | ||
from unittest import TestCase, main | ||
|
||
|
||
class ListNode: | ||
def __init__(self, val=0, next=None): | ||
self.val = val | ||
self.next = next | ||
|
||
|
||
class Solution: | ||
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: | ||
return self.solve_priority_queue(lists) | ||
|
||
""" | ||
Runtime: 7 ms (Beats 100.00%) | ||
Time Complexity: O(n * m) | ||
- lists의 길이 k만큼 조회에 O(k) | ||
- 힙의 크기가 최대 k이므로, heappush에 * O(log k) | ||
- heap의 크기는 최대 k이므로, | ||
- heappop하는데 O(k * log k) | ||
- heappush하는데 lists를 이루는 list를 이루는 모든 원소들의 총 갯수를 n이라 하면, O(n * log k) | ||
> O(k * log k) + O(k * log k) + O(n * log k) ~= O(max(k, n) * log k) = O(n * log k) | ||
Memory: 19.44 MB (Beats 58.42%) | ||
Space Complexity: O(k) | ||
> heap의 크기는 lists의 길이 k에 비례하므로, O(k) | ||
""" | ||
def solve_priority_queue(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: | ||
root = result = ListNode(None) | ||
heap = [] | ||
|
||
for i in range(len(lists)): | ||
if lists[i]: | ||
heappush(heap, (lists[i].val, i, lists[i])) | ||
|
||
while heap: | ||
node = heappop(heap) | ||
_, idx, result.next = node | ||
|
||
result = result.next | ||
if result.next: | ||
heappush(heap, (result.next.val, idx, result.next)) | ||
|
||
return root.next | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
self.assertEqual(True, True) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains 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,67 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def search(self, nums: List[int], target: int) -> int: | ||
return self.solve_binary_search(nums, target) | ||
|
||
""" | ||
Runtime: 4 ms (Beats 100.00%) | ||
Time Complexity: O(log n) | ||
> nums를 이진탐색으로 조회하므로 O(log n) | ||
Memory: 17.03 MB (Beats 10.00%) | ||
Space Complexity: O(1) | ||
> index를 위한 정수형 변수만 사용하므로 O(1) | ||
""" | ||
def solve_binary_search(self, nums: List[int], target: int) -> int: | ||
lo, hi = 0, len(nums) - 1 | ||
while lo < hi: | ||
mid = (lo + hi) // 2 | ||
if nums[mid] == target: | ||
return mid | ||
|
||
if nums[lo] <= nums[mid]: | ||
if nums[lo] <= target <= nums[mid]: | ||
hi = mid | ||
else: | ||
lo = mid + 1 | ||
|
||
else: | ||
if nums[mid] <= target <= nums[hi]: | ||
lo = mid + 1 | ||
else: | ||
hi = mid | ||
|
||
return lo if nums[lo] == target else -1 | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
nums = [4,5,6,7,0,1,2] | ||
target = 0 | ||
output = 4 | ||
self.assertEqual(Solution.search(Solution(), nums, target), output) | ||
|
||
def test_2(self): | ||
nums = [4,5,6,7,0,1,2] | ||
target = 3 | ||
output = -1 | ||
self.assertEqual(Solution.search(Solution(), nums, target), output) | ||
|
||
def test_3(self): | ||
nums = [1] | ||
target = 0 | ||
output = -1 | ||
self.assertEqual(Solution.search(Solution(), nums, target), output) | ||
|
||
def test_4(self): | ||
nums = [3, 1] | ||
target = 1 | ||
output = 1 | ||
self.assertEqual(Solution.search(Solution(), nums, target), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |