Skip to content

Commit

Permalink
Merge pull request #507 from lymchgmk/week8
Browse files Browse the repository at this point in the history
[EGON] Week8 Solutions
  • Loading branch information
EgonD3V authored Oct 4, 2024
2 parents 33741a7 + 4f95930 commit 2c92127
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 0 deletions.
58 changes: 58 additions & 0 deletions clone-graph/EGON.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from typing import Optional, TypeVar
from unittest import TestCase, main


# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []


class Solution:
def cloneGraph(self, node: Optional[Node]) -> Optional[Node]:
return self.solve(node)

"""
Runtime: 42 ms (Beats 45.48%)
Time Complexity: O(n)
Memory: 17.04 (Beats 8.15%)
Space Complexity: O(n), upper bound
"""
def solve(self, node: Optional[Node]) -> Optional[Node]:
clone_dict = {}
stack = [node]
visited = set()
while stack:
curr_node = stack.pop()
visited.add(curr_node.val)
if curr_node.val not in clone_dict:
clone_dict[curr_node.val] = Node(val=curr_node.val)

for neighbor in curr_node.neighbors:
if neighbor.val not in clone_dict:
clone_dict[neighbor.val] = Node(val=neighbor.val)

if neighbor.val not in visited:
clone_dict[curr_node.val].neighbors.append(clone_dict[neighbor.val])
clone_dict[neighbor.val].neighbors.append(clone_dict[curr_node.val])
stack.append(neighbor)

return clone_dict[node.val]


class _LeetCodeTestCases(TestCase):
def test_1(self):
node_dict = {1: Node(1), 2: Node(2), 3: Node(3), 4: Node(4)}
node_dict[1].neighbors = [node_dict[2], node_dict[4]]
node_dict[2].neighbors = [node_dict[1], node_dict[3]]
node_dict[3].neighbors = [node_dict[2], node_dict[4]]
node_dict[4].neighbors = [node_dict[1], node_dict[3]]

Solution.cloneGraph(Solution(), node_dict[1])
self.assertTrue("RUN")


if __name__ == '__main__':
main()
44 changes: 44 additions & 0 deletions longest-common-subsequence/EGON.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from unittest import TestCase, main


class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
return self.solve_dp(text1, text2)

"""
Runtime: 441 ms (Beats 85.60%)
Time Complexity: O(m * n)
- text1, text2์˜ ๊ธธ์ด๋ฅผ ๊ฐ๊ฐ m, n์ด๋ผ ํ•˜๋ฉด ์ด์ค‘ for๋ฌธ ์กฐํšŒ์— O(m * n)
- i. dp ๋ฐฐ์—ด ๊ฐ’ ๊ฐฑ์‹ ์—์„œ ๊ธฐ์กด๊ฐ’ +1์— O(1)
- ii. dp ๋ฐฐ์—ด ๊ฐ’ ๊ฐฑ์‹ ์—์„œ 2๊ฐœ ํ•ญ์— ๋Œ€ํ•œ max ์—ฐ์‚ฐ์— O(2), upper bound
> O(m * n) * O(2) ~= O(m * n)
Memory: 41.81 (Beats 55.93%)
Space Complexity: O(m * n)
> row์˜ ๊ธธ์ด๊ฐ€ n์ด๊ฐ€ col์˜ ๊ธธ์ด๊ฐ€ m์ธ 2์ฐจ์› ๋ฐฐ์—ด dp ์‚ฌ์šฉ์— O(m * n)
"""
def solve_dp(self, text1: str, text2: str) -> int:
dp = [[0] * (len(text2) + 1) for _ in range(len(text1) + 1)]
for idx1 in range(len(text1)):
for idx2 in range(len(text2)):
if text1[idx1] == text2[idx2]:
dp[idx1 + 1][idx2 + 1] = dp[idx1][idx2] + 1
else:
dp[idx1 + 1][idx2 + 1] = max(dp[idx1 + 1][idx2], dp[idx1][idx2 + 1])

return dp[-1][-1]


class _LeetCodeTestCases(TestCase):
def test_1(self):
text1 = "abcde"
text2 = "ace"
output = 3
self.assertEqual(
Solution().longestCommonSubsequence(text1, text2),
output
)


if __name__ == '__main__':
main()
48 changes: 48 additions & 0 deletions longest-repeating-character-replacement/EGON.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from unittest import TestCase, main
from collections import defaultdict


class Solution:
def characterReplacement(self, s: str, k: int) -> int:
return self.solve_sliding_window(s, k)

"""
Runtime: 63 ms (Beats 98.40%)
Time Complexity: O(n)
- s์— ๋Œ€ํ•ด ์กฐํšŒํ•˜๋Š”๋ฐ O(n)
- dict์ธ counter๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ๋ฌธ์ž์˜ ๋นˆ๋„์ˆ˜ ์ฒดํฌ, ๋ถ„๊ธฐ์ฒ˜๋ฆฌ, most_common_char ๊ฐฑ์‹ ์— O(1)
- ํ˜„์žฌ ์ตœ์žฅ ๊ธธ์ด ๊ณ„์‚ฐ์— int ๊ณ„์‚ฐ๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ O(1)
> O(n) * O(1) ~= O(n)
Memory: 16.54 (Beats 76.70%)
Space Complexity: O(n), upper bound
- left, right ๊ฐ™์€ int ์ธ๋ฑ์Šค ๋ณ€์ˆ˜ ํ• ๋‹น์— O(1)
- most_common_char๊ฐ™์€ str ๋ณ€์ˆ˜ ํ• ๋‹น์— O(1)
- dict์ธ counter์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๋Š” s์˜ ๋ชจ๋“  ๋ฌธ์ž๊ฐ€ ๋‹ค๋ฅด๊ณ  k์˜ ํฌ๊ธฐ๊ฐ€ len(s)์ธ ๊ฒฝ์šฐ์ด๋ฏ€๋กœ O(n), upper bound
> O(n), upper bound
"""
def solve_sliding_window(self, s: str, k: int) -> int:
left = right = 0
counter, most_common_char = defaultdict(int), ""
for right in range(len(s)):
counter[s[right]] += 1
if counter[most_common_char] < counter[s[right]]:
most_common_char = s[right]

if (right - left + 1) - counter[most_common_char] > k:
counter[s[left]] -= 1
left += 1

return right - left + 1


class _LeetCodeTestCases(TestCase):
def test_1(self):
s = "AABBCC"
k = 2
output = 4
self.assertEqual(Solution.characterReplacement(Solution(), s, k), output)


if __name__ == '__main__':
main()
79 changes: 79 additions & 0 deletions merge-two-sorted-lists/EGON.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from typing import Optional
from unittest import TestCase, main


class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next


class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
return self.solve(list1, list2)

"""
Runtime: 36 ms (Beats 71.91%)
Time Complexity: O(m + n)
> list1์˜ ๊ธธ์ด๋ฅผ m, list2์˜ ๊ธธ์ด๋ฅผ n์ด๋ผ ํ•  ๋•Œ, list1๊ณผ list2 ๋ชจ๋‘ ๋๊นŒ์ง€ ์กฐํšŒํ•˜๋ฏ€๋กœ O(n + m)
Memory: 16.62 (Beats 37.59%)
Space Complexity: O(m + n)
> result์˜ ๊ธธ์ด๋Š” list1์˜ ๊ธธ์ด์™€ list2์˜ ๊ธธ์ด์˜ ํ•ฉ๊ณผ ๊ฐ™์œผ๋ฏ€๋กœ O(m + n)
"""
def solve(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
result = ListNode()
node = result
while list1 or list2:
if list1 and list2:
if list1.val < list2.val:
node.next = list1
node = node.next
list1 = list1.next
else:
node.next = list2
node = node.next
list2 = list2.next

elif list1 and not list2:
node.next = list1
node = node.next
list1 = list1.next

elif not list1 and list2:
node.next = list2
node = node.next
list2 = list2.next

else:
break

return result.next


class _LeetCodeTestCases(TestCase):
def test_1(self):
list1 = ListNode(
val=1,
next=ListNode(
val=2,
next=ListNode(
val=4
)
)
)
list2 = ListNode(
val=1,
next=ListNode(
val=3,
next=ListNode(
val=4
)
)
)
output = [1,1,2,3,4,4]
self.assertEqual(Solution.mergeTwoLists(Solution(), list1, list2), output)


if __name__ == '__main__':
main()
41 changes: 41 additions & 0 deletions sum-of-two-integers/EGON.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from unittest import TestCase, main


class Solution:
def getSum(self, a: int, b: int) -> int:
return self.solve_bit(a, b)

"""
Runtime: 26 ms (Beats 94.94%)
Time Complexity: O(log max(a, b)) ~= O(1)
- a์™€ b๋ฅผ and ์—ฐ์‚ฐ ํ›„ ์™ผ์ชฝ์œผ๋กœ shiftํ•œ ๊ฐ’์„ b์— ํ• ๋‹นํ•˜๋Š”๋ฐ ๋ชจ๋‘ ๋น„ํŠธ์—ฐ์‚ฐ์ด๋ฏ€๋กœ O(1)
- b์˜ ๊ฐ’์ด ์™ผ์ชฝ shift์— ์˜ํ•ด ๊ฐ์†Œํ•˜๋ฏ€๋กœ log(b)
- ๋‹จ b์˜ ๊ฐ’์€ a & b์— ์˜ํ•ด ๊ฒฐ์ •๋˜๋ฏ€๋กœ log max(a, b)
- ์ „์ œ ์กฐ๊ฑด์—์„œ a, b๋Š” ๋ชจ๋‘ ์ ˆ๋Œ€๊ฐ’ 1000 ์ดํ•˜์˜ ๊ฐ’์ด๋ฏ€๋กœ, ์ตœ๋Œ€ 10ํšŒ์˜ shift ์—ฐ์‚ฐ๋งŒ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, O(10) ~= O(1)
> O(log max(a, b)) < O(10) ~= O(1)
Memory: 16.52 (Beats 18.98%)
Space Complexity: O(1)
> input์— ๋ฌด๊ด€ํ•˜๊ฒŒ ์ •์ˆ˜ํ˜• ๋ณ€์ˆ˜๋“ค๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ O(1)
"""
def solve_bit(self, a: int, b: int) -> int:
COMPLEMENT_MASK = 0xFFF

while b != 0:
carry = a & b
a = (a ^ b) & COMPLEMENT_MASK
b = (carry << 1) & COMPLEMENT_MASK

return a if a <= 0x7FF else ~(a ^ COMPLEMENT_MASK)


class _LeetCodeTestCases(TestCase):
def test_1(self):
a = -1
b = 1
output = 0
self.assertEqual(Solution().getSum(a, b), output)


if __name__ == '__main__':
main()

0 comments on commit 2c92127

Please sign in to comment.