diff --git a/2. Add Two Numbers/note.md b/2. Add Two Numbers/note.md new file mode 100644 index 0000000..a5878e7 --- /dev/null +++ b/2. Add Two Numbers/note.md @@ -0,0 +1,39 @@ +# step1 + +time: 30:28 + +解法は2つ思いつく. + +一つは linked list と数字の相互変換メソッドを定義してそれらを使用する方法. time complexity は O(N+M). space complexity は O(1). + +もう一つは同時に2つの linked list をたどりつつ新しい linked list を作る方法. time complexity は O(max(N, M)), space complexity は O(1). + +わかりやすさをとるか, 定数倍の性能差をとるか. + +多分求められているのは後者の方だと思う&前回は前者で実装したので後者で実装してみる. carry に注意. full adder みたいなものになりそう. + +l1, l2 が None じゃないかで 2 x 2 = 4 通りある時の条件分岐の書き方がいつもわからない. 素直に 4 つ書くのが無難か. + +変数の取り扱いが難しい. node を付け足す処理を共通化するなら digit_sum = None として事前に定義し後々値を入れればいいが, 考慮忘れの条件分岐に進んだとしたら None のままになっているのが怖い. + +あと l1 = l1.next しても良いのか. 呼び出し元の l1 が変化してしまうのではないのか. Python の参照渡しとかリテラルに対する勉強が足りない. + +l1, l2, carry ともに None のときは, sum_cursor の prev の next 変数を None にしないといけないが, そのためには sum_cursor_prev のような形で以前の位置の cursor を持っておく必要がある. うまく表現できないが, その一つのケースのために prev を持つのは複雑度が増して気持ち悪い感じがする. 代替案として, sum_root_node の一番最初の node は dummy の node を置いて, l1.val + l2.val + carry > 0 の場合はケツに node を追加するような実装にすれば問題なさそう. + +なんとかできたが, すごい読みにくいコードな気がする. やはり前者の実装方式のほうが良かったな. + +# step2 + +leetcode の解答を見た感じ, dummy head を用いるというアイデアは良かった. +None を 0 とすることでコードを簡潔にできそうだ. +あと部分問題に分けることで, recursive に解くこともできる. + +また, l1 = l1.next としても良いのか問題だが, l1 に再代入しているため問題ない. + +https://github.com/Mike0121/LeetCode/tree/main/Arai60/02.%20Add%20Two%20Numbers +https://github.com/hayashi-ay/leetcode/pull/24/files +こちらを参考に, recursive と loop 版で実装してみる. + +recursive で実装するときに, carry を考慮した関数を作るが, これはどこに置けばいいだろうか. メソッド内に関数を書くのはあまり経験がないので違和感を感じるが, carry を考慮した関数は外から呼び出すことはないので, メソッド内に書くのが良いのかもしれない. + +条件分岐もなくなり, digit_sum = None と初期化する問題も解消された. diff --git a/2. Add Two Numbers/old.py b/2. Add Two Numbers/old.py new file mode 100644 index 0000000..b9ae1f5 --- /dev/null +++ b/2. Add Two Numbers/old.py @@ -0,0 +1,34 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def listNodeToNumber(self, l: ListNode) -> int: + node = l + power = 1 + number = 0 + + while node is not None: + number += power * node.val + power *= 10 + node = node.next + + return number + + def numberToListNode(self, number: int) -> ListNode: + start = ListNode(val=number % 10) + now = start + number //= 10 + while number > 0: + now.next = ListNode(val=number % 10) + now = now.next + number //= 10 + return start + + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + l1num = self.listNodeToNumber(l1) + l2num = self.listNodeToNumber(l2) + return self.numberToListNode(l1num + l2num) + + \ No newline at end of file diff --git a/2. Add Two Numbers/step1.py b/2. Add Two Numbers/step1.py new file mode 100644 index 0000000..10817de --- /dev/null +++ b/2. Add Two Numbers/step1.py @@ -0,0 +1,32 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + sum_root_node = ListNode() + sum_cursor = sum_root_node + carry = 0 + while True: + digit_sum = None + if l1 is None and l2 is None: + if carry != 0: + sum_cursor.next = ListNode(val=carry) + break + if l1 is not None and l2 is None: + digit_sum = carry + l1.val + l1 = l1.next + elif l1 is None and l2 is not None: + digit_sum = carry + l2.val + l2 = l2.next + else: + digit_sum = carry + l1.val + l2.val + l1 = l1.next + l2 = l2.next + carry = digit_sum // 10 + digit_value = digit_sum % 10 + sum_cursor.next = ListNode(val=digit_value) + sum_cursor = sum_cursor.next + return sum_root_node.next + diff --git a/2. Add Two Numbers/step2_loop.py b/2. Add Two Numbers/step2_loop.py new file mode 100644 index 0000000..054916f --- /dev/null +++ b/2. Add Two Numbers/step2_loop.py @@ -0,0 +1,24 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + sum_dummy_head = ListNode() + sum_cursor = sum_dummy_head + carry = 0 + while l1 is not None or l2 is not None or carry > 0: + l1_digit = l1.val if l1 else 0 + l2_digit = l2.val if l2 else 0 + digit_sum = l1_digit + l2_digit + carry + carry = digit_sum // 10 + digit_val = digit_sum % 10 + + sum_cursor.next = ListNode(digit_val) + sum_cursor = sum_cursor.next + l1 = l1.next if l1 else None + l2 = l2.next if l2 else None + return sum_dummy_head.next + + diff --git a/2. Add Two Numbers/step2_recursive.py b/2. Add Two Numbers/step2_recursive.py new file mode 100644 index 0000000..7c045b7 --- /dev/null +++ b/2. Add Two Numbers/step2_recursive.py @@ -0,0 +1,20 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + def add_two_numbers_helper(l1: Optional[ListNode], l2: Optional[ListNode], carry: int) -> Optional[ListNode]: + if l1 is None and l2 is None and carry == 0: + return None + l1_val = l1.val if l1 else 0 + l2_val = l2.val if l2 else 0 + digit_sum = l1_val + l2_val + carry + sum_head = ListNode(digit_sum % 10) + l1_next = l1.next if l1 else None + l2_next = l2.next if l2 else None + sum_head.next = add_two_numbers_helper(l1_next, l2_next, digit_sum // 10) + return sum_head + return add_two_numbers_helper(l1, l2, 0) + diff --git a/2. Add Two Numbers/step3.py b/2. Add Two Numbers/step3.py new file mode 100644 index 0000000..a656494 --- /dev/null +++ b/2. Add Two Numbers/step3.py @@ -0,0 +1,20 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + def add_two_numbers_helper(l1: Optional[ListNode], l2: Optional[ListNode], carry: int) -> Optional[ListNode]: + if l1 is None and l2 is None and carry == 0: + return None + l1_val = l1.val if l1 else 0 + l2_val = l2.val if l2 else 0 + digit_sum = l1_val + l2_val + carry + + sum_root_node = ListNode(val=digit_sum%10) + l1_next = l1.next if l1 else None + l2_next = l2.next if l2 else None + sum_root_node.next = add_two_numbers_helper(l1_next, l2_next, digit_sum // 10) + return sum_root_node + return add_two_numbers_helper(l1, l2, 0) \ No newline at end of file