Skip to content

Commit

Permalink
feat : solve with python
Browse files Browse the repository at this point in the history
  • Loading branch information
changmuk.im committed Sep 17, 2024
1 parent 193f10b commit fbb65e7
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 0 deletions.
47 changes: 47 additions & 0 deletions container-with-most-water/EGON.py
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()
86 changes: 86 additions & 0 deletions design-add-and-search-words-data-structure/EGON.py
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()
55 changes: 55 additions & 0 deletions longest-increasing-subsequence/EGON.py
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)
- 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()
49 changes: 49 additions & 0 deletions spiral-matrix/EGON.py
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()
58 changes: 58 additions & 0 deletions valid-parentheses/EGON.py
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()

0 comments on commit fbb65e7

Please sign in to comment.