Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions 2. Add Two Numbers/2. Add Two Numbers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
step1
解く問題:https://leetcode.com/problems/add-two-numbers/description/
1つ目のノードには1の位、2つ目のノードには10の位、・・・と格納されている。
1つ目のノードの値+2つ目のノードの値×10+3つ目のノードの値×100というように計算してそれぞれのリストの値を求める。
それらを足した数を1の位から格納していく。
割り算の余りを考えれば、各桁の数を取り出せそう。
n÷10の余りをkとする。
kが1の位の数
n = (n-k)/10とすれば繰り返し処理にできそう。
ここまで思いついたことをコードにしてみる。
ある数を1の位からノードにして格納する方法で悩んでいる。
数字は取り出せるが、次のノードへの連結が難しい。
dummyを用意してそこを始点とすると上手くいきそう。
とりあえず書いてみた。
sumで判定を行っているので、一番最初のsumが0の時にリストが返されないことに気づいた。
sumが0の時の処理を加えた。
とりあえず実行できた。
```python3
# 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]:
l1_number = 0
l2_number = 0

#l1の数字を求める
node = l1
digit = 1
while node is not None:
l1_number += node.val * digit
digit = digit * 10
node = node.next

#l2の数字を求める
node = l2
digit = 1
while node is not None:
l2_number += node.val * digit
digit = digit * 10
node = node.next

sum = l1_number + l2_number

if sum == 0:
node = ListNode(0)
return node

dummy = ListNode()
last_added_node = dummy
#sumの1の位から順にリストを作成する
while sum != 0:
node_val = sum % 10
sum = (sum - node_val) // 10

node = ListNode(node_val)
last_added_node.next = node
last_added_node = node

return dummy.next
```

step2
他の人のコードを見てみた。
多くの人が同じ桁のノードごとに計算を行っていた。
なぜこのやり方でやるのかわからない。
と思っていたら、araiさんの動画で説明があった。
動画でこの問題は大きな数字を扱うためにこのような操作を行っているらしい。
確かに最初に数字を計算する手法では、もしノード数が100だった場合に100桁の数字を扱うことになる。
100桁の数字は64bitで表現できない。他の言語ではこのアルゴリズムは使えない。
c++で上手くいかなかった人がいた。https://github.com/5103246/LeetCode_Arai60/pull/5/commits/475690037f777b12e6f01dfd3335fd7c2fbcb5db
また、大きな数字の割り算を何度も行うことになる。
同じ桁のノードごとに演算を行う方が良いと思った。
極端な入力などを自分の頭で動かしてみるなどすれば、大きな数字を扱えないことに気づけたのかもしれない。
Pythonは何桁まで使えるのか気なった。
https://docs.python.org/ja/3.14/library/stdtypes.html#numeric-types-int-float-complex 
整数には精度の制限がないらしい
それをどのように実現しているのかgeminiに聞いた。
この問題と同じように桁ごとに分割して格納しているらしい。2^30進数らしい。
Pythonの整数型の実装コード https://github.com/python/cpython/blob/main/Objects/longobject.c
そのため桁ごとに計算する方針で解くことにする。
各桁の足し算を行う際に、数字を記録しておいて後で、まとめて足すコード https://github.com/resumit30minutes/leetcode-arai60-practice/blob/7c31041bc3f35ffa52f6637ef74afaf9d644f4a0/leetcode/add_two_numbers/step4.py
順に足していっているコード https://github.com/05ryt31/leetcode/blob/main/2-add-two-numbers/step3.py
まとめて足すコードの方が、足し算の式が一本にまとまっており何をしているのかわかりやすかったので、こちらのやり方でコードを書くことにする。
divmodという関数があるらしい。名前の通り、入力した2つの数のdivとmodを返す。
```python3
# 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]:
dummy = ListNode()
fixed_tail = dummy
carry = 0

while l1 is not None or l2 is not None or carry != 0:
node1_val = 0
if l1 is not None:
node1_val = l1.val
l1 = l1.next

node2_val = 0
if l2 is not None:
node2_val = l2.val
l2 = l2.next

total = node1_val + node2_val + carry

digit = total % 10
fixed_tail.next = ListNode(digit)
fixed_tail = fixed_tail.next
carry = total // 10

return dummy.next
```
step3
```python3
# 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]:
dummy = ListNode()
fixed_tail = dummy
carry = 0

while l1 is not None or l2 is not None or carry != 0:
node1_val = 0
if l1 is not None:
node1_val = l1.val
l1 = l1.next

node2_val = 0
if l2 is not None:
node2_val = l2.val
l2 = l2.next

total = node1_val + node2_val + carry

digit = total % 10
fixed_tail.next = ListNode(digit)
fixed_tail = fixed_tail.next

carry = total // 10

return dummy.next
```
43 changes: 43 additions & 0 deletions 2. Add Two Numbers/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
step1
解く問題:https://leetcode.com/problems/add-two-numbers/description/
1つ目のノードには1の位、2つ目のノードには10の位、・・・と格納されている。
1つ目のノードの値+2つ目のノードの値×10+3つ目のノードの値×100というように計算してそれぞれのリストの値を求める。
それらを足した数を1の位から格納していく。
割り算の余りを考えれば、各桁の数を取り出せそう。
n÷10の余りをkとする。
kが1の位の数
n = (n-k)/10とすれば繰り返し処理にできそう。
ここまで思いついたことをコードにしてみる。
ある数を1の位からノードにして格納する方法で悩んでいる。
数字は取り出せるが、次のノードへの連結が難しい。
dummyを用意してそこを始点とすると上手くいきそう。
とりあえず書いてみた。
sumで判定を行っているので、一番最初のsumが0の時にリストが返されないことに気づいた。
sumが0の時の処理を加えた。
とりあえず実行できた。

step2
他の人のコードを見てみた。
多くの人が同じ桁のノードごとに計算を行っていた。
なぜこのやり方でやるのかわからない。
と思っていたら、araiさんの動画で説明があった。
動画でこの問題は大きな数字を扱うためにこのような操作を行っているらしい。
確かに最初に数字を計算する手法では、もしノード数が100だった場合に100桁の数字を扱うことになる。
100桁の数字は64bitで表現できない。他の言語ではこのアルゴリズムは使えない。
c++で上手くいかなかった人がいた。https://github.com/5103246/LeetCode_Arai60/pull/5/commits/475690037f777b12e6f01dfd3335fd7c2fbcb5db
また、大きな数字の割り算を何度も行うことになる。
同じ桁のノードごとに演算を行う方が良いと思った。
極端な入力などを自分の頭で動かしてみるなどすれば、大きな数字を扱えないことに気づけたのかもしれない。
Pythonは何桁まで使えるのか気なった。
https://docs.python.org/ja/3.14/library/stdtypes.html#numeric-types-int-float-complex 
整数には精度の制限がないらしい
それをどのように実現しているのかgeminiに聞いた。
この問題と同じように桁ごとに分割して格納しているらしい。2^30進数らしい。
Pythonの整数型の実装コード https://github.com/python/cpython/blob/main/Objects/longobject.c
そのため桁ごとに計算する方針で解くことにする。
各桁の足し算を行う際に、数字を記録しておいて後で、まとめて足すコード https://github.com/resumit30minutes/leetcode-arai60-practice/blob/7c31041bc3f35ffa52f6637ef74afaf9d644f4a0/leetcode/add_two_numbers/step4.py
順に足していっているコード https://github.com/05ryt31/leetcode/blob/main/2-add-two-numbers/step3.py
まとめて足すコードの方が、足し算の式が一本にまとまっており何をしているのかわかりやすかったので、こちらのやり方でコードを書くことにする。
divmodという関数があるらしい。名前の通り、入力した2つの数のdivとmodを返す。

step3
46 changes: 46 additions & 0 deletions 2. Add Two Numbers/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
```python3
# 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]:
l1_number = 0
l2_number = 0

#l1の数字を求める
node = l1
digit = 1
while node is not None:
l1_number += node.val * digit
digit = digit * 10
node = node.next

#l2の数字を求める
node = l2
digit = 1
while node is not None:
l2_number += node.val * digit
digit = digit * 10
node = node.next

sum = l1_number + l2_number

if sum == 0:
node = ListNode(0)
return node
Comment on lines +30 to +32
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この方法だと0を特別扱いする必要がありますね。


dummy = ListNode()
Comment on lines +30 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

表記の一貫性がない部分が気になりました。
ListNodeのvalの初期値は0となっているので、ListNode()で良いかなと思いました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

個人的にはこの初期値は使わないのでなんでもいいという意味合いだと思うので、上とはものが違うというのでいいかと思います。

last_added_node = dummy
#sumの1の位から順にリストを作成する
while sum != 0:
node_val = sum % 10
sum = (sum - node_val) // 10

node = ListNode(node_val)
last_added_node.next = node
last_added_node = node

return dummy.next
```
32 changes: 32 additions & 0 deletions 2. Add Two Numbers/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
```python3
# 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]:
dummy = ListNode()
fixed_tail = dummy
carry = 0

while l1 is not None or l2 is not None or carry != 0:
node1_val = 0
if l1 is not None:
node1_val = l1.val
l1 = l1.next

node2_val = 0
if l2 is not None:
node2_val = l2.val
l2 = l2.next

total = node1_val + node2_val + carry

digit = total % 10
fixed_tail.next = ListNode(digit)
fixed_tail = fixed_tail.next
carry = total // 10

return dummy.next
```
34 changes: 34 additions & 0 deletions 2. Add Two Numbers/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
step3
```python3
# 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]:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

どうやら両方が None である可能性はこの問題では気にしなくて良いようですが、来たら None が返りますね。

dummy = ListNode()
fixed_tail = dummy
carry = 0

while l1 is not None or l2 is not None or carry != 0:
node1_val = 0
if l1 is not None:
node1_val = l1.val
l1 = l1.next

node2_val = 0
if l2 is not None:
node2_val = l2.val
l2 = l2.next

total = node1_val + node2_val + carry

digit = total % 10
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

今回は10で割ったあまりで、今回の解法でいくと次のfixed_tailのvalだと思うので、それが伝わる命名のfixed_tail_valなどだとより意味が伝わり読み手に親切かなと思いました。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かにvalをつけた方が意味が分かりやすいですね。勉強になります。

fixed_tail.next = ListNode(digit)
fixed_tail = fixed_tail.next

carry = total // 10

return dummy.next
```