-
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 #467 from lymchgmk/feat/weak6
[EGON] Week 6 Solutions
- Loading branch information
Showing
5 changed files
with
295 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,47 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def maxArea(self, height: List[int]) -> int: | ||
return self.solveWithTwoPointer(height) | ||
|
||
""" | ||
Runtime: 527 ms (Beats 47.12%) | ||
Time Complexity: O(n) | ||
- 투 포인터의 총합 조회 범위가 height의 길이와 같으므로 O(n) | ||
- area 갱신을 위한 계산에서 항이 2개인 max와 항이 2개인 min 중첩에 O(2) * O(2) | ||
> O(n) * O(4) ~= O(n) | ||
Memory: 29.61 MB (Beats 38.93%) | ||
Space Complexity: O(1) | ||
> 정수형 변수들만 사용했으므로 O(1) | ||
""" | ||
def solveWithTwoPointer(self, height: List[int]) -> int: | ||
left, right = 0, len(height) - 1 | ||
area = 0 | ||
while left < right: | ||
area = max(area, (right - left) * min(height[right], height[left])) | ||
|
||
if height[left] <= height[right]: | ||
left += 1 | ||
else: | ||
right -= 1 | ||
|
||
return area | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
height = [1, 8, 6, 2, 5, 4, 8, 3, 7] | ||
output = 49 | ||
self.assertEqual(Solution.maxArea(Solution(), height), output) | ||
|
||
def test_2(self): | ||
height = [1, 1] | ||
output = 1 | ||
self.assertEqual(Solution.maxArea(Solution(), height), 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,86 @@ | ||
from unittest import TestCase, main | ||
|
||
|
||
class Node: | ||
|
||
def __init__(self, key): | ||
self.key = key | ||
self.isWordEnd = False | ||
self.children = {} | ||
|
||
|
||
class Trie: | ||
WILD_CARD = '.' | ||
|
||
def __init__(self): | ||
self.root = Node(None) | ||
|
||
def insert(self, word: str) -> None: | ||
curr_node = self.root | ||
for char in word: | ||
if char not in curr_node.children: | ||
curr_node.children[char] = Node(char) | ||
|
||
curr_node = curr_node.children[char] | ||
curr_node.isWordEnd = True | ||
|
||
def search(self, node: Node, word: str, idx: int) -> bool: | ||
if idx == len(word): | ||
return node.isWordEnd | ||
|
||
for idx in range(idx, len(word)): | ||
if word[idx] == self.WILD_CARD: | ||
for child in node.children.values(): | ||
if self.search(child, word, idx + 1) is True: | ||
return True | ||
else: | ||
return False | ||
|
||
if word[idx] in node.children: | ||
return self.search(node.children[word[idx]], word, idx + 1) | ||
else: | ||
return False | ||
|
||
|
||
""" | ||
Runtime: 1810 ms (Beats 22.46%) | ||
Time Complexity: | ||
> addWord: word의 길이만큼 순회하므로 O(L) | ||
> search: | ||
- word의 평균 길이를 W이라하면, | ||
- '.'가 포함되어 있지 않는 경우 O(W), early return 가능하므로 upper bound | ||
- '.'가 포함되어 있는 경우, 해당 노드의 child만큼 재귀, trie의 평균 자식 수를 C라 하면 O(W) * O(C), early return 가능하므로 upper bound | ||
- trie의 평균 자식 수는 addWord의 실행횟수 C'에 선형적으로 비레(겹치는 char가 없는 경우 upper bound) | ||
> O(W) * O(C) ~= O(W) * O(C') ~= O(W * C'), upper bound | ||
Memory: 66.78 MB (Beats 12.26%) | ||
Space Complexity: O(1) | ||
> addWord: | ||
- 삽입한 word의 평균 길이 L만큼 Node가 생성 및 Trie에 추가, O(L) | ||
- addWord의 실행횟수 C'에 비례, O(C') | ||
> O(L) * O(C') ~= O(L * C') | ||
> search: | ||
> 만들어진 Trie와 패러미터 word, 정수 변수 idx를 사용하므로 O(1) | ||
""" | ||
class WordDictionary: | ||
|
||
def __init__(self): | ||
self.trie = Trie() | ||
|
||
def addWord(self, word: str) -> None: | ||
self.trie.insert(word) | ||
|
||
def search(self, word: str) -> bool: | ||
return self.trie.search(self.trie.root, word, 0) | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
wordDictionary = WordDictionary() | ||
wordDictionary.addWord("at") | ||
self.assertEqual(wordDictionary.search(".at"), False) | ||
|
||
|
||
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 typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def lengthOfLIS(self, nums: List[int]) -> int: | ||
return self.solve_with_Memo_BS(nums) | ||
|
||
""" | ||
Runtime: 68 ms (Beats 86.42%) | ||
Time Complexity: O(n * log n) | ||
- nums 배열 조회에 O(n) | ||
- 최악의 경우 num의 모든 원소에 대해 bisect_left 실행가능, O(log n) upper bound | ||
> O(n) * O(log n) ~= O(n * log n) | ||
Memory: 16.92 MB (Beats 29.49%) | ||
Space Complexity: O(n) | ||
> 최대 크기가 n인 lis 배열 사용에 O(n) | ||
""" | ||
def solve_with_Memo_BS(self, nums: List[int]) -> int: | ||
|
||
def bisect_left(lis: List[int], target: int): | ||
lo, hi = 0, len(lis) | ||
while lo < hi: | ||
mid = lo + (hi - lo) // 2 | ||
if lis[mid] < target: | ||
lo = mid + 1 | ||
else: | ||
hi = mid | ||
|
||
return lo | ||
|
||
lis = [] | ||
for num in nums: | ||
if not lis: | ||
lis.append(num) | ||
continue | ||
|
||
if lis[-1] < num: | ||
lis.append(num) | ||
else: | ||
lis[bisect_left(lis, num)] = num | ||
|
||
return len(lis) | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
prices = [10,9,2,5,3,7,101,18] | ||
output = 4 | ||
self.assertEqual(Solution.lengthOfLIS(Solution(), prices), 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,49 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def spiralOrder(self, matrix: List[List[int]]) -> List[int]: | ||
return self.solve(matrix) | ||
|
||
""" | ||
Runtime: 37 ms (Beats 44.53%) | ||
Time Complexity: O(MAX_R * MAX_C) | ||
Memory: 16.56 MB (Beats 43.42%) | ||
Space Complexity: O(1) | ||
- result를 제외하고 matrix의 값을 변경해서 visited 분기 | ||
""" | ||
def solve(self, matrix: List[List[int]]) -> List[int]: | ||
MAX_R, MAX_C = len(matrix), len(matrix[0]) | ||
DIRS = ((0, 1), (1, 0), (0, -1), (-1, 0)) | ||
result = [] | ||
r, c, dir_idx = 0, -1, 0 | ||
for _ in range(MAX_R * MAX_C): | ||
r += DIRS[dir_idx][0] | ||
c += DIRS[dir_idx][1] | ||
|
||
if 0 <= r < MAX_R and 0 <= c < MAX_C and matrix[r][c] is not None: | ||
result.append(matrix[r][c]) | ||
matrix[r][c] = None | ||
else: | ||
r -= DIRS[dir_idx][0] | ||
c -= DIRS[dir_idx][1] | ||
dir_idx = (dir_idx + 1) % len(DIRS) | ||
r += DIRS[dir_idx][0] | ||
c += DIRS[dir_idx][1] | ||
result.append(matrix[r][c]) | ||
matrix[r][c] = None | ||
|
||
return result | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] | ||
output = [1,2,3,4,8,12,11,10,9,5,6,7] | ||
self.assertEqual(Solution.spiralOrder(Solution(), matrix), 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,58 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def isValid(self, s: str) -> bool: | ||
return self.solveWithStack(s) | ||
|
||
""" | ||
Runtime: 34 ms (Beats 66.54%) | ||
Time Complexity: O(n) | ||
> 문자열 s의 길이 L만큼 조회하므로 O(n), early return이 있으므로 upper bound | ||
Memory: 16.59 MB (Beats 50.97%) | ||
Space Complexity: O(n) | ||
- close_p_dict의 크기는 상수로 처리 | ||
> 최대 길이가 L인 배열 stack을 사용했으므로 O(n) | ||
""" | ||
def solveWithStack(self, s: str) -> bool: | ||
close_p_dict = {')': '(', '}': '{', ']': '['} | ||
stack = [] | ||
for curr_p in s: | ||
if not stack or curr_p not in close_p_dict: | ||
stack.append(curr_p) | ||
continue | ||
|
||
if close_p_dict[curr_p] != stack[-1]: | ||
return False | ||
else: | ||
stack.pop() | ||
|
||
return not stack | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
s = "()" | ||
output = True | ||
self.assertEqual(Solution.isValid(Solution(), s), output) | ||
|
||
def test_2(self): | ||
s = "()[]{}" | ||
output = True | ||
self.assertEqual(Solution.isValid(Solution(), s), output) | ||
|
||
def test_3(self): | ||
s = "(]" | ||
output = False | ||
self.assertEqual(Solution.isValid(Solution(), s), output) | ||
|
||
def test_4(self): | ||
s = "([])" | ||
output = True | ||
self.assertEqual(Solution.isValid(Solution(), s), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |