Skip to content

Commit 92359ca

Browse files
authored
Merge pull request #433 from lymchgmk/feat/week4
[EGON] Week 4 Solutions
2 parents 33875e8 + fd4a944 commit 92359ca

File tree

5 files changed

+313
-0
lines changed

5 files changed

+313
-0
lines changed

longest-consecutive-sequence/EGON.py

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class Solution:
6+
def longestConsecutive(self, nums: List[int]) -> int:
7+
return self.solveWithDict(nums)
8+
9+
"""
10+
Runtime: 486 ms (Beats 40.61%)
11+
Time Complexity:
12+
- nums 배열 조회하며 연산에 O(n)
13+
- 크기가 n인 node_dict.items()을 조회, visited에 의해 각 노드당 한 번만 방문,
14+
- visited가 set이므로 갱신 및 확인에 O(1)
15+
- 2개 항에 대해 max 연산하므로 O(2)로, 총 O(n)
16+
> O(n) + O(n) ~= O(n)
17+
18+
Memory: 44.62 MB (Beats 5.00%)
19+
Space Complexity: O(n)
20+
- value가 크기 2짜리 배열이고 key가 최대 n인 dict 변수 사용에 O(2n)
21+
- 최대 크기가 n인 visited 사용에 O(n)
22+
> O(2n) + O(n) ~= O(n)
23+
"""
24+
def solveWithDict(self, nums: List[int]) -> int:
25+
node_dict = {}
26+
for num in nums:
27+
curr_node = [num, num]
28+
if num - 1 in node_dict:
29+
prev_node = node_dict[num - 1]
30+
curr_node[0] = prev_node[0]
31+
prev_node[1] = curr_node[1]
32+
if num + 1 in node_dict:
33+
post_node = node_dict[num + 1]
34+
curr_node[1] = post_node[1]
35+
post_node[0] = curr_node[0]
36+
node_dict[num] = curr_node
37+
38+
max_length = 0
39+
visited = set()
40+
for key, (prev_key, post_key) in node_dict.items():
41+
while prev_key not in visited and prev_key in node_dict:
42+
visited.add(prev_key)
43+
prev_key = node_dict[prev_key][0]
44+
while post_key not in visited and post_key in node_dict:
45+
visited.add(post_key)
46+
post_key = node_dict[post_key][1]
47+
curr_length = post_key - prev_key + 1
48+
max_length = max(max_length, curr_length)
49+
50+
return max_length
51+
52+
53+
class _LeetCodeTestCases(TestCase):
54+
def test_1(self):
55+
nums = [100, 4, 200, 1, 3, 2]
56+
output = 4
57+
self.assertEqual(Solution.longestConsecutive(Solution(), nums), output)
58+
59+
def test_2(self):
60+
nums = [0, 3, 7, 2, 5, 8, 4, 6, 0, 1]
61+
output = 9
62+
self.assertEqual(Solution.longestConsecutive(Solution(), nums), output)
63+
64+
65+
if __name__ == '__main__':
66+
main()

maximum-subarray/EGON.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class Solution:
6+
def maxProduct(self, nums: List[int]) -> int:
7+
return self.solveWithDP(nums)
8+
9+
"""
10+
Runtime: 71 ms (Beats 61.13%)
11+
Time Complexity: O(n)
12+
- dp 배열 초기화를 위한 nums.copy()에 O(n)
13+
- range(1, L) 조회하며 조건에 따라 연산에 O(n - 1)
14+
- range(L) 조회하며 max 계산에 O(n)
15+
> O(n) + O(n - 1) + O(n) ~= O(n)
16+
17+
Memory: 17.75 MB (Beats 11.09%)
18+
Space Complexity: O(n)
19+
- 크기가 n인 배열 2개 사용했으므로 2 * O(n)
20+
> O(2n) ~= O(n)
21+
"""
22+
def solveWithDP(self, nums: List[int]) -> int:
23+
L = len(nums)
24+
forward_product, backward_product = nums.copy(), nums.copy()
25+
for i in range(1, L):
26+
if forward_product[i - 1] != 0:
27+
forward_product[i] *= forward_product[i - 1]
28+
29+
if backward_product[L - i] != 0:
30+
backward_product[L - i - 1] *= backward_product[L - i]
31+
32+
result = nums[0]
33+
for i in range(L):
34+
result = max(result, forward_product[i], backward_product[i])
35+
36+
return result
37+
38+
39+
class _LeetCodeTestCases(TestCase):
40+
def test_1(self):
41+
nums = [2,3,-2,4]
42+
output = 6
43+
self.assertEqual(Solution.maxProduct(Solution(), nums), output)
44+
45+
def test_2(self):
46+
nums = [-2,0,-1]
47+
output = 0
48+
self.assertEqual(Solution.maxProduct(Solution(), nums), output)
49+
50+
def test_3(self):
51+
nums = [-2]
52+
output = -2
53+
self.assertEqual(Solution.maxProduct(Solution(), nums), output)
54+
55+
def test_4(self):
56+
nums = [0,-3,-2,-3,-2,2,-3,0,1,-1]
57+
output = 72
58+
self.assertEqual(Solution.maxProduct(Solution(), nums), output)
59+
60+
def test_5(self):
61+
nums = [7, -2, -4]
62+
output = 56
63+
self.assertEqual(Solution.maxProduct(Solution(), nums), output)
64+
65+
66+
if __name__ == '__main__':
67+
main()

missing-number/EGON.py

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class Solution:
6+
def missingNumber(self, nums: List[int]) -> int:
7+
return self.solveWithSet(nums)
8+
9+
"""
10+
Runtime: 118 ms (Beats 31.19%)
11+
Time Complexity:
12+
- 크기가 n + 1인 List를 set로 변환에 O(n + 1)
13+
- nums 배열 조회하며 set.remove에 O(n) * O(1) ~= O(n)
14+
- 마지막 set에서 pop하는데 O(1)
15+
> O(n + 1) + O(n) + O(1) ~= O(n)
16+
17+
Memory: 18.56 MB (Beats 5.%)
18+
Space Complexity:
19+
- 크기가 n + 1인 set 사용에 O(n + 1)
20+
> O(n + 1) ~= O(n)
21+
"""
22+
def solveWithSet(self, nums: List[int]) -> int:
23+
range_set = set(range(0, len(nums) + 1))
24+
for num in nums:
25+
range_set.remove(num)
26+
27+
return range_set.pop()
28+
29+
30+
class _LeetCodeTestCases(TestCase):
31+
def test_1(self):
32+
nums = [3, 0, 1]
33+
output = 2
34+
self.assertEqual(Solution.missingNumber(Solution(), nums), output)
35+
36+
def test_2(self):
37+
nums = [0, 1]
38+
output = 2
39+
self.assertEqual(Solution.missingNumber(Solution(), nums), output)
40+
41+
def test_3(self):
42+
nums = [9, 6, 4, 2, 3, 5, 7, 0, 1]
43+
output = 8
44+
self.assertEqual(Solution.missingNumber(Solution(), nums), output)
45+
46+
47+
if __name__ == '__main__':
48+
main()

valid-palindrome/EGON.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from unittest import TestCase, main
2+
3+
4+
class Solution:
5+
def isPalindrome(self, s: str) -> bool:
6+
return self.solveWithTwoPointer(s)
7+
8+
"""
9+
Runtime: 43 ms (Beats 68.60%)
10+
Time Complexity: O(n)
11+
- s 문자열 iterable 조회하며 연산에 O(n)
12+
- range(0, length // 2) 조회에 O(n // 2)
13+
> O(n) + O(n // 2) ~= O(n)
14+
15+
Memory: 17.02 MB (Beats 54.30%)
16+
Space Complexity: O(n)
17+
- 최대 크기가 n인 trimmed_s 변수 할당에 O(n)
18+
> O(n)
19+
"""
20+
def solveWithPointer(self, s: str) -> bool:
21+
trimmed_s = ""
22+
for char in s:
23+
if char.isalpha() or char.isnumeric():
24+
trimmed_s += char.lower()
25+
26+
length = len(trimmed_s)
27+
for i in range(0, length // 2):
28+
if trimmed_s[i] != trimmed_s[length - i - 1]:
29+
return False
30+
else:
31+
return True
32+
33+
34+
class _LeetCodeTestCases(TestCase):
35+
def test_1(self):
36+
s = "A man, a plan, a canal: Panama"
37+
output = True
38+
self.assertEqual(Solution.isPalindrome(Solution(), s), output)
39+
40+
def test_2(self):
41+
s = "race a car"
42+
output = False
43+
self.assertEqual(Solution.isPalindrome(Solution(), s), output)
44+
45+
def test_3(self):
46+
s = " "
47+
output = True
48+
self.assertEqual(Solution.isPalindrome(Solution(), s), output)
49+
50+
51+
if __name__ == '__main__':
52+
main()

word-search/EGON.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from typing import List
2+
from unittest import TestCase, main
3+
4+
5+
class Solution:
6+
def exist(self, board: List[List[str]], word: str) -> bool:
7+
return self.solveWithDFS(board, word)
8+
9+
"""
10+
Runtime: 5005 ms (Beats 27.48%)
11+
Time Complexity: O((MAX_R ** 2) * (MAX_C ** 2)), upper bound
12+
- 이중 for문 조회에 O(MAX_R * MAX_C)
13+
- node 하나당 조회하는 DIRS의 크기가 4이고, 최대 word의 길이만큼 반복하므로 O(4 * L)
14+
- 단 early return하므로 이는 upper bound
15+
> O(MAX_R * MAX_C) * O(4L) ~= O(MAX_R * MAX_C * L)
16+
17+
Memory: 16.59 MB (Beats 69.71%)
18+
Space Complexity:
19+
- MAX_R * MAX_C 격자의 칸마다 stack이 생성될 수 있으므로 O(MAX_R * MAX_C)
20+
- node의 크기는 visited에 지배적이고(curr_word 무시 가정), visited의 크기는 최대 L
21+
> O(MAX_R * MAX_C) * O(L) ~= O(MAX_R * MAX_C * L)
22+
"""
23+
def solveWithDFS(self, board: List[List[str]], word: str) -> bool:
24+
MAX_R, MAX_C, MAX_IDX = len(board), len(board[0]), len(word)
25+
DIRS = ((-1, 0), (1, 0), (0, -1), (0, 1))
26+
27+
for r in range(MAX_R):
28+
for c in range(MAX_C):
29+
if board[r][c] == word[0]:
30+
stack = [(r, c, 0, board[r][c], set([(r, c)]))]
31+
while stack:
32+
curr_r, curr_c, curr_idx, curr_word, curr_visited = stack.pop()
33+
34+
if curr_word == word:
35+
return True
36+
37+
for dir_r, dir_c in DIRS:
38+
post_r, post_c, post_idx = curr_r + dir_r, curr_c + dir_c, curr_idx + 1
39+
if (post_r, post_c) in curr_visited:
40+
continue
41+
if not (0 <= post_r < MAX_R and 0 <= post_c < MAX_C):
42+
continue
43+
if not (post_idx < MAX_IDX and board[post_r][post_c] == word[post_idx]):
44+
continue
45+
46+
post_visited = curr_visited.copy()
47+
post_visited.add((post_r, post_c))
48+
stack.append((post_r, post_c, post_idx, curr_word + word[post_idx], post_visited))
49+
50+
return False
51+
52+
53+
class _LeetCodeTestCases(TestCase):
54+
def test_1(self):
55+
board = [["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]]
56+
word = "ABCCED"
57+
output = True
58+
self.assertEqual(Solution.exist(Solution(), board, word), output)
59+
60+
def test_2(self):
61+
board = [["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]]
62+
word = "SEE"
63+
output = True
64+
self.assertEqual(Solution.exist(Solution(), board, word), output)
65+
66+
def test_3(self):
67+
board = [["A", "B", "C", "E"], ["S", "F", "C", "S"], ["A", "D", "E", "E"]]
68+
word = "ABCB"
69+
output = False
70+
self.assertEqual(Solution.exist(Solution(), board, word), output)
71+
72+
def test_4(self):
73+
board = [["A","B","C","E"],["S","F","E","S"],["A","D","E","E"]]
74+
word = "ABCESEEEFS"
75+
output = True
76+
self.assertEqual(Solution.exist(Solution(), board, word), output)
77+
78+
79+
if __name__ == '__main__':
80+
main()

0 commit comments

Comments
 (0)