Skip to content

Add Two Numbers #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 1 commit 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
268 changes: 268 additions & 0 deletions addTwoNumbers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
# Add Two Numbers

## step1

所要時間 20m

valを置き換えた後にcarryを計算してしまった
l1とl2が同じ長さでない場合
一番最後に繰り上げがある場合

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

node1 = l1
node2 = l2
node_sum = l_sum

carry = 0
val = 0

while node1 is not None or node2 is not None:
if node1 is not None and node2 is not None:
val = node1.val + node2.val + carry
elif node1 is None:
val = node2.val + carry
elif node2 is None:
val = node1.val + carry

carry = val//10
Copy link

Choose a reason for hiding this comment

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

二項演算子の両隣にスペースを空けるか空けないか、ソースコード間で統一することをおすすめいたします。

val = val%10
node_sum.next = ListNode(val)

if node1 is not None:
node1 = node1.next
if node2 is not None:
node2 = node2.next

node_sum = node_sum.next

if carry != 0:
node_sum.next = ListNode(carry)

return l_sum.next

```

- is not None を何回も使わなければいけないのが気になる。他の方法はないのだろうか?

## step2 読みやすくする&他の人の解法を見る

### [一つ目](https://leetcode.com/problems/add-two-numbers/solutions/3675747/beats-100-c-java-python-beginner-friendly/)

```python
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
dummyHead = ListNode(0)
Copy link

Choose a reason for hiding this comment

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

変数名は lower_snake で書くことをおすすめいたします。

https://peps.python.org/pep-0008/#function-and-variable-names

Variable names follow the same convention as function names.

https://google.github.io/styleguide/pyguide.html#316-naming

local_var_name

LeetCode で指定されているものについては、例外として扱ってよいと思います。

tail = dummyHead
carry = 0

while l1 is not None or l2 is not None or carry != 0:
digit1 = l1.val if l1 is not None else 0
digit2 = l2.val if l2 is not None else 0

sum = digit1 + digit2 + carry
digit = sum % 10
carry = sum // 10

newNode = ListNode(digit)
tail.next = newNode
tail = tail.next

l1 = l1.next if l1 is not None else None
l2 = l2.next if l2 is not None else None

result = dummyHead.next
dummyHead.next = None
return result

```

- carry != 0をwhileに追加しているので最後の繰り上がりを別で考える必要がない
- 直接sumを求めるのではなくdigit1,digit2などを経由している。こちらの方が良い気がする。
- 自分の書き方だとなぜvalを求める式が変わるのかがわからない。
- sumとdigitが別の変数になっている。
- 自分は両方valで同じ名前としていた。わかりにくいのでやめた方が良いと思う。
- if節を一行で書いている
- 簡単なif文なのでこちらで書いてもいいかも
- [三項演算子について](https://www.geeksforgeeks.org/ternary-operator-in-python/)よく知らないので調べてみた
- If else
- a = "true value" if 条件 else "false value"
- ネストされたif else
- a = "true value 1" if 条件1 else "true value 2" if 条件2 else "false value2"
- ネストするなら普通に書いたほうがわかりやすそう
- タプル
- a = ((false value, true value)\[条件])
- falseとtrueの順番が直感に反する
- 条件が0を返したら0番目の要素、1を返したら1番目の要素ということらしい
- 辞書
- a = ({True: "true value", False: "false value"}\[条件])
- タプルは知らなかったらわからないからこっちの方が親切だと思った。
- Lambda
- a = ((lambda: "false value", lambda:"true value")\[条件]())
- dummyHead.next = Noneと最後にしている。最後のLinkedList.nextがNoneであることを明示している。
- ListNode classは デフォルトでnext = Noneとしているので必要ない気がする。
- これをやらない場合どのようなエラーが考えられるのだろうか。
```python
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
```


### [二つ目]()
- 再帰で解く方法

```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode],carry = 0) -> Optional[ListNode]:
if not l1 and not l2 and not carry:
return None

l1_val = l1.val if l1 else 0
l2_val = l2.val if l2 else 0
total = carry + l1_val + l2_val
carry = total // 10
current_node = ListNode(total % 10)

l1_next = l1.next if l1 else None
l2_next = l2.next if l2 else None
current_node.next = self.addTwoNumbers(l1_next, l2_next, carry)

return current_node
```
- not ではなく is Noneと書くべきではないのだろうか?
- not l1, not l2はis None だがnot carry はis 0である。そこを示した方がわかりやすい気がする
Copy link

Choose a reason for hiding this comment

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

ここらへんは、派閥ありますね。周りに聞いて合わせましょう。
Google Style Guide は is not None 派。
https://google.github.io/styleguide/pyguide.html#2144-decision
Pep8 はどちらでもいいのかしら。
https://peps.python.org/pep-0008/#programming-recommendations:~:text=Also%2C%20beware%20of%20writing%20if%20x%20when%20you%20really%20mean%20if%20x%20is%20not%20None

- whileループを再帰で代用している。この方法は知らなかったので勉強になる。

### [三つ目](https://github.com/Mike0121/LeetCode/pull/41/files)
- 再帰で解いている

```python
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
def get_value(node: Optional[ListNode]) -> int:
if node is None:
return 0
return node.val

def next_node(node: Optional[ListNode]) -> Optional[ListNode]:
if node is None:
return None
return node.next

def add_two_numbers_helper(node1: Optional[ListNode] , node2: Optional[ListNode], carry: int) -> Optional[ListNode]:
if not (node1 or node2 or carry):
return None

value1 = get_value(node1)
value2 = get_value(node2)
total = value1 + value2 + carry
node = ListNode(total % 10)
carry = total // 10
node.next = _add_two_numbers_helper(next_node(node1), next_node(node2), carry)
return node

return _add_two_numbers_helper(l1, l2, 0)
```
- 同じことをするなら関数化すればいい
- 簡単すぎるので今回はどちらでもいいがこの発想は持っておきたい
- `node = ListNode(total % 10)`のような書き方をするよりはtotal % 10に変数を割り当てたほうが読みやすいのではないか

### [四つめ](https://github.com/h1rosaka/arai60/pull/7/files/d94c4e1281bc3fd371bdddb2d0d2b95a010aaa4f#diff-c655c7f146b306e01c4b8ca0d6739d1fcc21f08b78456fb0dbf415fca6864c5a)
nodeの数を数字にして、和を計算してから改めてListNodeにする

```python
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
dummy_head = ListNode(-1)
tail = dummy_head

def sum_all_node_vals(base: int, head: Optional[ListNode])->int:
total = base
node = head
digit_position = 0
while node:
total += node.val * (10**digit_position)
node = node.next
digit_position += 1
return total

total = sum_all_node_vals(0, l1)
total = sum_all_node_vals(total, l2)

for digit in reversed(str(total)):
tail.next = ListNode(int(digit))
tail = tail.next

return dummy_head.next

```
- 思いつかなかったが確かにこの方法もできる

### 読みやすくする

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

node1 = l1
node2 = l2
node_sum = l_sum

carry = 0
val = 0

while node1 is not None or node2 is not None or carry != 0:

node1_val = node1.val if node1 is not None else 0
Copy link

Choose a reason for hiding this comment

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

この周辺、インデントでタブとスペースが混ざっているように思います。スペースでインデントすることをおすすめいたします。

https://peps.python.org/pep-0008/#indentation

Use 4 spaces per indentation level.

https://google.github.io/styleguide/pyguide.html#34-indentation

Indent your code blocks with 4 spaces.

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。なんとなく使っていたのですがTabはエディタなどが違うと異なって表示されるためspaceが推奨されているのですね。これから注意したいと思います。

node2_val = node2.val if node2 is not None else 0

total = node1_val + node2_val + carry

carry = total//10
val = total%10
node_sum.next = ListNode(val)

node1 = node1.next if node1 is not None else None
node2 = node2.next if node2 is not None else None

node_sum = node_sum.next

return l_sum.next

```
- 基本的に一つ目のコードを参考にして書き換えた。
### step3
最終的なコードはstep2と同じで以下のようになった。

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

node1 = l1
node2 = l2
node_sum = l_sum

carry = 0
val = 0
while node1 is not None or node2 is not None or carry != 0:
node1_val = node1.val if node1 is not None else 0
node2_val = node2.val if node2 is not None else 0
total = node1_val + node2_val + carry

carry = total//10
val = total%10
node_sum.next = ListNode(val)

node1 = node1.next if node1 is not None else None
node2 = node2.next if node2 is not None else None
node_sum = node_sum.next

return l_sum.next

```