Skip to content

2. Add Two Numbers.md #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
216 changes: 216 additions & 0 deletions 2. Add Two Numbers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
2. Add Two Numbers.md
思考順に書いていく
誰かの発言の引用は「」

step1 not accepted
```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
l1_node = l1
result = l2_node = l2

while l1_node and l2_node:
l2_node.val += l1_node.val
if l2_node.val > 9:
l2_node.val = l2_node.val - 10
if l2_node.next is None:
l2_node.next = ListNode(0)
l2_node.next.val += 1
l1_node = l1_node.next
l2_node = l2_node.next

return result
```
以下は何の値を間違ったか
```python
Input:
l1 =
[2,4,9]
l2 =
[5,6,4,9]

Output:
[7,0,4,10]

Expected:
[7,0,4,0,1]
```

繰り上げした後に、その次の桁も繰り上げした場合の繰り上げも考えなければいけないが実装が思いつかないので断念

CodingNinjaさんの動画を視聴した(https://www.youtube.com/watch?v=DFDTaCGlzTY)
l1、l2とは違う新しいリストを用意。l1、l2の計算結果をそこにまとめる考え方。

他の人のコードを読む。
(https://github.com/SanakoMeine/leetcode/pull/6)
step1では場合分けして、その都度連結リストを作っていくやり方

商と余りを求められるdivmod間数を知ったが、//と%使う方が分かりやすいと思うので使わない。

そもそも変数名carryってなんだろと思ったので辞書引いた。
「桁上げ

ある桁での加算結果が、その桁で表せる数を超えたとき、1つ上の桁に加えられる数のこと。たとえば、ある桁の加算が7+5=12の場合、桁上げは1となる。キャリーまたはキャリービット、繰り上げとも呼ぶ。」
  (https://kotobank.jp/word/%E6%A1%81%E4%B8%8A%E3%81%92-3167#:~:text=%E3%81%82%E3%82%8B%E6%A1%81%E3%81%A7%E3%81%AE%E5%8A%A0%E7%AE%97,%E3%82%AD%E3%83%A3%E3%83%AA%E3%83%BC%E3%83%93%E3%83%83%E3%83%88%E3%80%81%E7%B9%B0%E3%82%8A%E4%B8%8A%E3%81%92%E3%81%A8%E3%82%82%E5%91%BC%E3%81%B6%E3%80%82)

digitは0~9までの数字の中の一つ
  (https://ejje.weblio.jp/content/digit)

下の人のgitも読んだ。
(https://github.com/t0hsumi/leetcode/pull/5)
step2の間数の中に間数を書いて処理分けする方法は良いと思ったけど、今回は間数わざわざ作らない方がシンプルになりそう。

discord漁っているとodaさんの「継承や特殊メソッド(__setitem__ など)についての期待感は、なんらかの言語最低一つで知らないと怖いくらいです。」
という発言があったので、ここら辺ドキュメント読むことにする。

あーなんでわざわざ間数作ってval求めてるかっていったらNoneの時に値0を吐き出すようにすることでエラーを避けてるのか。
すごいけど、これ初見で書く気持ちになれないから、新しい定義書くのはやめる方針で行く。

CodingNinjaさんのコードが自然な感じがするので、それを参考にする。

step2
```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode])-> Optional[ListNode]:
sentinel = ListNode()
sentinel_node = sentinel
total = carry = 0

while l1 or l2 or carry > 0:
total = carry

if l1:
total += l1.val
l1 = l1.next
if l2:
total += l2.val
l2 = l2.next

digit = total % 10
carry = total // 10
sentinel_node.next = ListNode(digit)
sentinel_node = sentinel_node.next
return sentinel.next
```

CodingNinjaさんのコードを参考に変数名など分かりやすいように変更した。
if文を使うことでLinked ListがNoneになっても飛ばせるのが勉強になった。
暗記しなくてもスラスラ書けたので、これが自然なんだろう。このコードでstep3にいく

sentinelのlを書き忘れるタイポが多いためdummyに変更する。
```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode])-> Optional[ListNode]:
dummy = ListNode()
dummy_node = dummy
total = carry = 0

while l1 or l2 or carry > 0:
total = carry

if l1:
total += l1.val
l1 = l1.next
if l2:
total += l2.val
l2 = l2.next

digit = total % 10
carry = total // 10
dummy_node.next = ListNode(digit)
dummy_node = dummy_node.next
return dummy.next
```
step3
タイポ多くて手間取った
1回目 1分57秒
2回目 2分1秒
3回目 2分9秒

```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode])-> Optional[ListNode]:
dummy = ListNode()
dummy_node = dummy
Copy link

Choose a reason for hiding this comment

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

dummy_node って、このコードにおいてはどういう意味でしょうか。
計算済みの桁の最後ということではないでしょうか。上から読んでいく人がなんとなくそれが予期できる名前がいいと思います。

Copy link
Owner Author

@lilnoahhh lilnoahhh Jan 14, 2025

Choose a reason for hiding this comment

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

最初はdummyという連結リスト、筆算でいう最後の計算結果を書く場所の上を動き、その各位を見ていくという気持ちでdummy_nodeと名付けました。

しかし、ご指摘のように上から読むと分からないため「current_digit_node」に変更しようと思います。ありがとうございます。

total = carry = 0

Choose a reason for hiding this comment

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

totalはループの中に入れましょう。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ご指摘ありがとうございます。フィードバックを元に修正してみます!


while l1 or l2 or carry > 0:
total = carry
if l1:
total += l1.val
l1 = l1.next

if l2:
total += l2.val
l2 = l2.next

digit = total % 10
carry = total // 10
dummy_node.next = ListNode(digit)
dummy_node = dummy_node.next
return dummy.next
```
時間計算量はO(N)でl1,l2のうち要素数が多い方の要素数がN
空間計算量はO(N)も同様。

以下はレビューを受けて修正したコード。
digid⇨digit
totalをループの中に入れた。
```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode])-> Optional[ListNode]:
dummy = ListNode()
current_digit_node = dummy
carry = 0

while l1 or l2 or carry > 0:
total = carry
if l1:
total += l1.val
l1 = l1.next

if l2:
total += l2.val
l2 = l2.next

digit = total % 10
carry = total // 10
current_digit_node.next = ListNode(digit)
current_digit_node = current_digit_node.next
Copy link

Choose a reason for hiding this comment

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

ここでcurrent_digit_nodeを更新するまで、current_digit_nodeは「現在計算している桁数を指すノード」ではなく、それより一つ小さい桁のノードとなっているので、自分なら単にnodeにしてしまうかなと思いました。

もしくは、

current_digit_node.next = ListNode()
current_digit_node = current_digit_node.next

をループの最初に書いて、ループの最後でcurrent_digit_node.val = digitとするかなと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

返信遅くなり申し訳ありません。

ご指摘の通りcurrent_digit_nodeだと誤解をうみそうですね。
current_digit_nodeだと長いし、提案していただいたnodeで書くようにしてみます!
レビューありがとうございます。

return dummy.next
```

たしかにtotalをわざわざ最初に初期化する必要なかった。こっちの方がすっきりしている。

さらにレビューを受けて変更した。
current_digit_node → node

```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode])-> Optional[ListNode]:
dummy = ListNode()
node = dummy
carry = 0

while l1 or l2 or carry > 0:
total = carry
if l1:
total += l1.val
l1 = l1.next

if l2:
total += l2.val
l2 = l2.next

digit = total % 10
carry = total // 10
node.next = ListNode(digit)
node = node.next
return dummy.next
```
こっちのほうがシンプル。あとcurrentはpreviousやnextとの対比で使うので避けた方がいいという話を見たので
その視点からもnodeにした方が良かった。