Skip to content
31 changes: 31 additions & 0 deletions Reverse Linked List/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# step1

ループ処理の最中でノードを反転させていく方法が一番最初に思いついた。(というか、多分やったことがあって記憶にあった)
2分くらいで手順を書き出して、それをコード化することができた。

# step2

ループでのアプローチ以外に
- 再帰
- スタック
があることを知った。

## 再帰について

Choose a reason for hiding this comment

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

再帰の書き方については2種類あるようなのでそちらも見ておくと勉強になるかもしれません
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.x5w37bodndgj


今回再帰でコード書いてみると通りはするけど、実際にノードの連結数に明記がないので不適。(LeetCodeの環境なら大丈夫なコードになってしまうから)

Choose a reason for hiding this comment

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

問題文の制約に

The number of nodes in the list is the range [0, 5000].

とありました。またLeetcodeではrecursionlimitが550000に設定されているようです。
ということであくまでこの問題の制約内かつLeetcode上であれば再帰を使っても大丈夫という判断ができそうです。


時間計算量はO(N), 空間計算量はO(N)

## スタック

アプローチはとても自然で他人が書いたコードでも読みやすいと思った。
ただ空間計算量がO(N)になり、他のアプローチを考えるとデメリット。

時間計算量はO(N), 空間計算量はO(N)

## step3

AIもつかってリファクタリングをした。
再帰はベースケースとエッジケースを最初に明記して後続の処理をよりシンプルに書くように変更


17 changes: 17 additions & 0 deletions Reverse Linked List/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None
node = head

while node:
tmp = node.next
node.next = prev
prev = node
node = tmp
return prev

16 changes: 16 additions & 0 deletions Reverse Linked List/step2-using-iterative.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
previous_node, current_node = None, head

while current_node:
tmp = current_node.next
current_node.next = previous_node
previous_node = current_node
current_node = tmp
return previous_node

19 changes: 19 additions & 0 deletions Reverse Linked List/step2-using-recursive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:

Choose a reason for hiding this comment

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

個人的にはif head is None:が自然かなという気がしました。
少し前に同様の議論があったのでそちらもご参考いただけると幸いです。
Kaichi-Irie/leetcode-python#20 (comment)

return None

new_head = head
Copy link

Choose a reason for hiding this comment

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

この部分の役割がぴんとこず、上のbase caseにまとめたほうがすっきりしそうだなと思いましたが実際step3ではそのようにされていてそちらのほうが意図が取りやすかったです。


if head.next:
new_head = self.reverseList(head.next)
head.next.next = head
head.next = None

return new_head

27 changes: 27 additions & 0 deletions Reverse Linked List/step2-using-stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return None

stack = []
node = head
while node:
stack.append(node)
node = node.next

new_head = stack.pop()
tail = new_head

while stack:
new_tail = stack.pop()
tail.next = new_tail
tail = tail.next

tail.next = None
return new_head

15 changes: 15 additions & 0 deletions Reverse Linked List/step3-using-iteration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
previous_node, current_node = None, head

Choose a reason for hiding this comment

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

previousは書き手の視点から見た名前ですが、最終的には逆順リストの先頭になるものですのでそれが分かる名前にしておくと伝わりやすいかもしれません。


while current_node:
tmp = current_node.next

Choose a reason for hiding this comment

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

スコープはかなり狭いので問題無いかなという気もしつつ、基本的にtmpという名前は情報が無いので少し避けたい気持ちがあります。
「反転していない残りの連結リストの先頭」なので自分なら単にrestとかhead_restとかにするかなと考えました。

current_node.next = previous_node
previous_node = current_node
current_node = tmp
return previous_node
16 changes: 16 additions & 0 deletions Reverse Linked List/step3-using-recursion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head

new_head = self.reverseList(head.next)
head.next.next = head

Choose a reason for hiding this comment

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

head.next.nextは分かっていないと読み手がちょっと混乱する書き方でもあるかなと思うので、一旦head.nextを別の変数に代入してあげてもいいかもしれません。

head.next = None

return new_head

27 changes: 27 additions & 0 deletions Reverse Linked List/step3-using-stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head

stack = []
node = head

while node:
stack.append(node)
node = node.next

tail = stack.pop()

Choose a reason for hiding this comment

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

tailより「逆順リストの先頭」である名前だとreturnに来た時に直感的に分かりやすいかな、と個人的に思いました

Copy link

Choose a reason for hiding this comment

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

+1です。どういう意味でtailなのか明瞭でないように思います。

node = tail

while stack:
node.next = stack.pop()
node = node.next
node.next = None
Comment on lines +19 to +24

Choose a reason for hiding this comment

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

最初にstackから1つ取り出しておくのではなく、

  • whileに入るたびに1つ取り出してnodeに代入
  • node.nextをstackの一番上のノードに繋ぎかえる(無かったらNoneに繋ぐ)

とやって全てwhileの中に処理をまとめるというのもありかなと思いました。
(その場合は上の行はtail = stack[-1]とする必要があります)


return tail

Choose a reason for hiding this comment

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

細かいところで恐縮なのですがいくつかのファイルの最後に余分な空行が入っているのが少し気になりました。
どのエディタを使われているかにもよるのですが、例えばVS CodeであればTrim Final Newlinesという設定をONにしておくとファイル保存時に自動的に消してくれたりします。そのような設定をしてみてもいいかもしれません。

19 changes: 19 additions & 0 deletions Reverse Linked List/step4-using-iteration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head

new_head_node, current_node = None, head

while current_node:
rest_node_head = current_node.next
current_node.next = new_head_node
new_head_node = current_node
current_node = rest_node_head
return new_head_node

16 changes: 16 additions & 0 deletions Reverse Linked List/step4-using-recursion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head

new_head = self.reverseList(head.next)
new_previous_node = head.next
new_previous_node.next = head
head.next = None
return new_head

21 changes: 21 additions & 0 deletions Reverse Linked List/step4-using-stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
stack = []
node = head
while node:
stack.append(node)
node = node.next
new_head = stack.pop()
node = new_head
while stack:
node.next = stack.pop()
node = node.next
node.next = None
return new_head