-
Notifications
You must be signed in to change notification settings - Fork 0
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
total = carry = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. totalはループの中に入れましょう。 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 をループの最初に書いて、ループの最後で There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 返信遅くなり申し訳ありません。 ご指摘の通りcurrent_digit_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にした方が良かった。 | ||
|
||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dummy_node って、このコードにおいてはどういう意味でしょうか。
計算済みの桁の最後ということではないでしょうか。上から読んでいく人がなんとなくそれが予期できる名前がいいと思います。
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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」に変更しようと思います。ありがとうございます。