diff --git a/0138.Copy-List-with-Random-Pointer/memo.md b/0138.Copy-List-with-Random-Pointer/memo.md new file mode 100644 index 0000000..d9718dd --- /dev/null +++ b/0138.Copy-List-with-Random-Pointer/memo.md @@ -0,0 +1,28 @@ +# 138. Copy List with Random Pointer + +## step1 + +頭から実装するとstep1.pyとなった。 + +同じ処理が現れたので関数化したが、getattrなどが何度も現れてわかりづらい + +## step2 + +ソリューションを漁る + +https://leetcode.com/problems/copy-list-with-random-pointer/solutions/379056/python-solution-with-comments-on-using-a-xf3k/?envType=problem-list-v2&envId=7p5x763 + +再帰を使うのは思いつかなかった +```python +def copyRandomList(self, head: 'Optional[Node]', seen={None: None}) -> 'Optional[Node]': + """ O(N)TS """ + if head not in seen: + seen[head] = Node(head.val) + seen[head].next = self.copyRandomList(head.next, seen) + seen[head].random = self.copyRandomList(head.random, seen) + return seen[head] +``` + +https://leetcode.com/problems/copy-list-with-random-pointer/solutions/7052593/on-and-o1-solutions-by-russelldcosta-lbh8/?envType=problem-list-v2&envId=7p5x763 + +Hashmapを使わずに解ける。空間計算量がO(1)になる。 diff --git a/0138.Copy-List-with-Random-Pointer/step1.py b/0138.Copy-List-with-Random-Pointer/step1.py new file mode 100644 index 0000000..38e4c2e --- /dev/null +++ b/0138.Copy-List-with-Random-Pointer/step1.py @@ -0,0 +1,36 @@ +""" +# Definition for a Node. +""" + + +class Node: + def __init__(self, x: int, next: "Node" = None, random: "Node" = None): + self.val = int(x) + self.next = next + self.random = random + + +class Solution: + def copyRandomList(self, head: Node | None) -> Node | None: + if head is None: + return head + copy_head = Node(x=head.val) + original_to_copy = {head: copy_head} + node = head + node_copy = copy_head + while node is not None: + if node.next is not None: + if node.next in original_to_copy: + node_copy.next = original_to_copy[node.next] + else: + node_copy.next = Node(x=node.next.val) + original_to_copy[node.next] = node_copy.next + if node.random is not None: + if node.random in original_to_copy: + node_copy.random = original_to_copy[node.random] + else: + node_copy.random = Node(x=node.random.val) + original_to_copy[node.random] = node_copy.random + node = node.next + node_copy = node_copy.next + return copy_head diff --git a/0138.Copy-List-with-Random-Pointer/step1_revised.py b/0138.Copy-List-with-Random-Pointer/step1_revised.py new file mode 100644 index 0000000..f94f02e --- /dev/null +++ b/0138.Copy-List-with-Random-Pointer/step1_revised.py @@ -0,0 +1,42 @@ +""" +# Definition for a Node. +""" + + +class Node: + def __init__(self, x: int, next: "Node" = None, random: "Node" = None): + self.val = int(x) + self.next = next + self.random = random + + +class Solution: + def copyRandomList(self, head: Node | None) -> Node | None: + if head is None: + return head + + copy_head = Node(x=head.val) + original_to_copy = {head: copy_head} + node = head + node_copy = copy_head + + def update_attribute(node: Node, node_copy: Node, attribute: str) -> None: + nonlocal original_to_copy + if getattr(node, attribute) in original_to_copy: + setattr( + node_copy, attribute, original_to_copy[getattr(node, attribute)] + ) + else: + setattr(node_copy, attribute, Node(x=getattr(node, attribute).val)) + original_to_copy[getattr(node, attribute)] = getattr( + node_copy, attribute + ) + + while node is not None: + if node.next is not None: + update_attribute(node, node_copy, "next") + if node.random is not None: + update_attribute(node, node_copy, "random") + node = node.next + node_copy = node_copy.next + return copy_head diff --git a/0138.Copy-List-with-Random-Pointer/step2_wo_hashmap.py b/0138.Copy-List-with-Random-Pointer/step2_wo_hashmap.py new file mode 100644 index 0000000..b90783d --- /dev/null +++ b/0138.Copy-List-with-Random-Pointer/step2_wo_hashmap.py @@ -0,0 +1,44 @@ +class Node: + def __init__(self, x: int, next: "Node" = None, random: "Node" = None): + self.val = int(x) + self.next = next + self.random = random + + +class Solution: + def copyRandomList(self, head: "Node" | None) -> "Node" | None: + if head is None: + return None + + # original1->copy1->original2->copy2... + node = head + while node: + node_next = node.next + copy_node = Node(x=node.val) + node.next = copy_node + copy_node.next = node_next + node = node_next + + # コピーしたノードのrandomを繋ぐ + node = head + while node: + if node.random: + node.next.random = node.random.next + node = node.next.next + + # コピーを分離する + node = head + dummy_head = Node(0) + copy_node = dummy_head + + while node: + node_next = node.next.next + + copy_node_next = node.next + copy_node.next = copy_node_next + copy_node = copy_node_next + + node.next = node_next + node = node_next + + return dummy_head.next diff --git a/0138.Copy-List-with-Random-Pointer/step3_wo_hashmap.py b/0138.Copy-List-with-Random-Pointer/step3_wo_hashmap.py new file mode 100644 index 0000000..4df12a7 --- /dev/null +++ b/0138.Copy-List-with-Random-Pointer/step3_wo_hashmap.py @@ -0,0 +1,44 @@ +from __future__ import annotations + + +class Node: + def __init__(self, x: int, next: Node = None, random: Node = None): + self.val = int(x) + self.next = next + self.random = random + + +class Solution: + def copyRandomList(self, head: Node | None) -> Node | None: + if head is None: + return None + + node = head + while node: + node_next = node.next + copy_node = Node(x=node.val) + node.next = copy_node + copy_node.next = node_next + node = node_next + + node = head + while node: + if node.random: + node.next.random = node.random.next + node = node.next.next + + node = head + dummy_head = Node(0) + copy_node = dummy_head + + while node: + node_next = node.next.next + + copy_node_next = node.next + copy_node.next = copy_node_next + copy_node = copy_node_next + + node.next = node_next + node = node_next + + return dummy_head.next