Skip to content

Commit 348e0d4

Browse files
author
changmuk.im
committed
feat : solve with python
1 parent 6dd8755 commit 348e0d4

File tree

5 files changed

+443
-0
lines changed

5 files changed

+443
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from unittest import TestCase, main
2+
3+
4+
class Solution:
5+
def lengthOfLongestSubstring(self, s: str) -> int:
6+
return self.solve_sliding_window(s)
7+
8+
"""
9+
Runtime: 313 ms (Beats 8.97%)
10+
Time Complexity:
11+
- left가 0에서 len(s)까지 조회, right가 left + 1 부터 len(s)까지 조회하므로 O(n * (n + 1) / 2)
12+
- left가 조회할 때마다, 2항 max 연산하므로 * 2
13+
> O((n * (n + 1) / 2) * 2) ~= O(n ^ 2)
14+
15+
Memory: 16.51 (Beats 81.63%)
16+
Space Complexity: O(n)
17+
> checker가 최대 s의 길이만큼 커질 수 있으므로 O(n), upper bound
18+
"""
19+
def solve_two_pointer(self, s: str) -> int:
20+
if not s:
21+
return 0
22+
23+
max_length = 1
24+
for left in range(len(s)):
25+
if len(s) - left + 1 < max_length:
26+
return max_length
27+
28+
right = left + 1
29+
checker = set(s[left])
30+
while right < len(s):
31+
if s[right] in checker:
32+
break
33+
34+
checker.add(s[right])
35+
right += 1
36+
37+
max_length = max(max_length, len(checker))
38+
39+
return max_length
40+
41+
"""
42+
Runtime: 58 ms (Beats 46.47%)
43+
Time Complexity:
44+
- 중복 검사는 set을 사용하므로 O(1)
45+
- right가 len(s)까지 조회하므로 O(n)
46+
- right가 조회한 뒤 2항 max 연산하는데 O(2)
47+
- left가 최대 right까지 조회하고 right < len(s) 이므로 O(n), upper bound
48+
> O(n) * O(2) + O(n) ~= O(n)
49+
50+
Memory: 16.60 (Beats 41.73%)
51+
Space Complexity: O(n)
52+
> checker가 최대 s의 길이만큼 커질 수 있으므로 O(n), upper bound
53+
"""
54+
def solve_sliding_window(self, s: str) -> int:
55+
max_length = 0
56+
left = right = 0
57+
checker = set()
58+
while left < len(s) and right < len(s):
59+
while right < len(s) and s[right] not in checker:
60+
checker.add(s[right])
61+
right += 1
62+
63+
max_length = max(max_length, len(checker))
64+
65+
while left < len(s) and (right < len(s) and s[right] in checker):
66+
checker.remove(s[left])
67+
left += 1
68+
69+
return max_length
70+
71+
72+
class _LeetCodeTestCases(TestCase):
73+
def test_1(self):
74+
s = "pwwkew"
75+
output = 3
76+
self.assertEqual(Solution.lengthOfLongestSubstring(Solution(), s), output)
77+
78+
79+
if __name__ == '__main__':
80+
main()

number-of-islands/EGON.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
from collections import deque
2+
from typing import Generic, List, Optional, TypeVar
3+
from unittest import TestCase, main
4+
5+
6+
T = TypeVar('T')
7+
8+
9+
class Node(Generic[T]):
10+
def __init__(self, value: T):
11+
self.value = value
12+
self.prev = None
13+
self.post = None
14+
15+
16+
class Deque(Generic[T]):
17+
def __init__(self):
18+
self.head: Optional[Node[T]] = None
19+
self.tail: Optional[Node[T]] = None
20+
self.size = 0
21+
22+
def is_empty(self):
23+
return self.size == 0
24+
25+
def appendright(self, value: T):
26+
node = Node(value)
27+
if self.is_empty():
28+
self.head = self.tail = node
29+
else:
30+
node.prev = self.tail
31+
if self.tail:
32+
self.tail.post = node
33+
self.tail = node
34+
self.size += 1
35+
36+
def appendleft(self, value: T):
37+
node = Node(value)
38+
if self.is_empty():
39+
self.head = self.tail = node
40+
else:
41+
node.post = self.head
42+
if self.head:
43+
self.head.prev = node
44+
self.head = node
45+
self.size += 1
46+
47+
def popright(self) -> T:
48+
if self.is_empty():
49+
raise IndexError("Deque is empty!")
50+
51+
value = self.tail.value
52+
self.tail = self.tail.prev
53+
if self.tail:
54+
self.tail.post = None
55+
else:
56+
self.head = None
57+
self.size -= 1
58+
return value
59+
60+
def popleft(self) -> T:
61+
if self.is_empty():
62+
raise IndexError("Deque is empty!")
63+
64+
value = self.head.value
65+
self.head = self.head.post
66+
if self.head:
67+
self.head.prev = None
68+
else:
69+
self.tail = None
70+
self.size -= 1
71+
return value
72+
73+
74+
class Solution:
75+
def numIslands(self, grid: List[List[str]]) -> int:
76+
return self.solve_bfs_custom(grid)
77+
78+
"""
79+
Runtime: 243 ms (Beats 60.00%)
80+
Time Complexity: O(MAX_R * MAX_C)
81+
- 2차원 배열 grid를 조회하며 deq에 enqueue하는데 O(MAX_R * MAX_C)
82+
- deq의 원소 하나 당 DIRS 크기만큼 탐색에 O(4), 원소에 해당하는 grid의 값이 "0"인 경우 탐색하지 않으므로 upper bound
83+
- deque의 appendleft, popleft에 O(1)
84+
> O(MAX_R * MAX_C) * O(4) ~= O(MAX_R * MAX_C)
85+
86+
Memory: 18.82 (Beats 83.56%)
87+
Space Complexity: O(MAX_R * MAX_C)
88+
- visited 역할을 grid의 원소의 값을 변경하여 사용하였으므로 무시
89+
- deque의 최대 크기는 MAX_R * MAX_C 이므로 O(MAX_R * MAX_C), upper bound
90+
> O(MAX_R * MAX_C)
91+
"""
92+
def solve_bfs(self, grid: List[List[str]]) -> int:
93+
94+
def is_island(r: int, c: int) -> bool:
95+
nonlocal grid
96+
97+
if grid[r][c] != "1":
98+
return False
99+
100+
deq = deque([(r, c)])
101+
deq.appendleft((r, c))
102+
while deq:
103+
curr_r, curr_c = deq.popleft()
104+
grid[r][c] = "0"
105+
for dir_r, dir_c in DIRS:
106+
post_r, post_c = curr_r + dir_r, curr_c + dir_c
107+
if 0 <= post_r < MAX_R and 0 <= post_c < MAX_C and grid[post_r][post_c] == "1":
108+
grid[post_r][post_c] = "0"
109+
deq.appendleft((post_r, post_c))
110+
111+
return True
112+
113+
MAX_R, MAX_C = len(grid), len(grid[0])
114+
DIRS = ((-1, 0), (1, 0), (0, -1), (0, 1))
115+
count = 0
116+
for r in range(MAX_R):
117+
for c in range(MAX_C):
118+
count += 1 if is_island(r, c) else 0
119+
return count
120+
121+
"""
122+
Runtime: 283 ms (Beats 23.05%)
123+
Time Complexity: O(MAX_R * MAX_C)
124+
> solve_bfs와 동일
125+
Memory: 19.98 (Beats 44.38%)
126+
Space Complexity: O(MAX_R * MAX_C)
127+
> solve_bfs와 동일
128+
"""
129+
def solve_bfs_custom(self, grid: List[List[str]]) -> int:
130+
131+
def is_island(r: int, c: int) -> bool:
132+
nonlocal grid
133+
134+
if grid[r][c] != "1":
135+
return False
136+
137+
deq = Deque()
138+
deq.appendleft((r, c))
139+
while not deq.is_empty():
140+
curr_r, curr_c = deq.popleft()
141+
grid[r][c] = "0"
142+
for dir_r, dir_c in DIRS:
143+
post_r, post_c = curr_r + dir_r, curr_c + dir_c
144+
if 0 <= post_r < MAX_R and 0 <= post_c < MAX_C and grid[post_r][post_c] == "1":
145+
grid[post_r][post_c] = "0"
146+
deq.appendleft((post_r, post_c))
147+
148+
return True
149+
150+
MAX_R, MAX_C = len(grid), len(grid[0])
151+
DIRS = ((-1, 0), (1, 0), (0, -1), (0, 1))
152+
count = 0
153+
for r in range(MAX_R):
154+
for c in range(MAX_C):
155+
count += 1 if is_island(r, c) else 0
156+
return count
157+
158+
159+
class _LeetCodeTestCases(TestCase):
160+
def test_1(self):
161+
grid = [
162+
["1", "1", "0", "0", "0"],
163+
["1", "1", "0", "0", "0"],
164+
["0", "0", "1", "0", "0"],
165+
["0", "0", "0", "1", "1"]
166+
]
167+
output = 3
168+
self.assertEqual(Solution.numIslands(Solution(), grid), output)
169+
170+
171+
if __name__ == '__main__':
172+
main()

reverse-linked-list/EGON.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from typing import List, 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 description(self) -> List[int]:
12+
desc = []
13+
node = self
14+
while node:
15+
desc.append(node.val)
16+
node = node.next
17+
18+
return desc
19+
20+
21+
class Solution:
22+
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
23+
return self.solve_recursively(head)
24+
25+
"""
26+
Runtime: 41 ms (Beats 28.37%)
27+
Time Complexity: O(n)
28+
- Linked List의 모든 node를 순회하는데 O(n)
29+
- post 변수 할당, curr.next, prev와 curr의 참조 변경은 O(1)
30+
> O(n) * O(1) ~= O(n)
31+
32+
Memory: 17.66 (Beats 85.13%)
33+
Space Complexity: O(1)
34+
- Linked List의 크기와 무관한 ListNode 타입의 prev, curr, post 변수를 할당하여 사용
35+
> O(1)
36+
"""
37+
def solve_iteratively(self, head: Optional[ListNode]) -> Optional[ListNode]:
38+
prev, curr = None, head
39+
while curr:
40+
post = curr.next
41+
curr.next = prev
42+
prev, curr = curr, post
43+
44+
return prev
45+
46+
"""
47+
Runtime: 38 ms (Beats 50.06%)
48+
Time Complexity: O(n)
49+
- Linked List의 모든 node 만큼 재귀를 호출하므로 O(n)
50+
- post 변수 할당, curr.next의 참조 변경은 O(1)
51+
> O(n) * O(1) ~= O(n)
52+
53+
Memory: 17.78 (Beats 27.88%)
54+
Space Complexity: O(n)
55+
> Linked List의 모든 node 만큼 reverse 함수가 스택에 쌓이므로 O(n)
56+
"""
57+
def solve_recursively(self, head: Optional[ListNode]) -> Optional[ListNode]:
58+
def reverse(prev: Optional[ListNode], curr: Optional[ListNode]) -> Optional[ListNode]:
59+
if not curr:
60+
return prev
61+
62+
post = curr.next
63+
curr.next = prev
64+
return reverse(curr, post)
65+
66+
return reverse(None, head)
67+
68+
69+
70+
71+
class _LeetCodeTestCases(TestCase):
72+
def test_1(self):
73+
node1 = ListNode(val=1)
74+
node2 = ListNode(val=2)
75+
node3 = ListNode(val=3)
76+
node4 = ListNode(val=4)
77+
node5 = ListNode(val=5)
78+
node1.next = node2
79+
node2.next = node3
80+
node3.next = node4
81+
node4.next = node5
82+
83+
output = [5, 4, 3, 2, 1]
84+
self.assertEqual(Solution.reverseList(Solution(), node1).description(), output)
85+
86+
87+
if __name__ == '__main__':
88+
main()

0 commit comments

Comments
 (0)