-
Notifications
You must be signed in to change notification settings - Fork 0
Create ReverseLinkedCycle.md #8
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,120 @@ | ||
# 206.Reverse Linked Listを解きました。レビューの程よろしくお願いします。 | ||
|
||
## ## 参考にした方々(Pythonで書かれた直近5名) | ||
- https://github.com/olsen-blue/Arai60/pull/7/files | ||
- https://github.com/t0hsumi/leetcode/pull/7/files | ||
- https://github.com/rinost081/LeetCode/pull/8/files | ||
- https://github.com/katataku/leetcode/pull/7/files | ||
- https://github.com/ichika0615/arai60/pull/6/files | ||
|
||
## Step 1 | ||
### 考えたこと | ||
- Stackの問題らしい。Linked Listを順番に読んでいってstackに格納して、逆順に読み出した値を補完するLinked Listを番兵付きで作れば良さそう | ||
- が、Memory Limit Exceededで動かずギブアップ。下記は動かなかった時のコード。 | ||
|
||
```Python | ||
# Memory Limit Exceededで動かないコード | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
scan = head | ||
stack = [] | ||
|
||
while scan: | ||
stack.append(scan) | ||
scan = scan.next | ||
|
||
sentinel = ListNode(0, scan) | ||
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. sentinel.valは使わないので、わざわざ指定せずに 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. そもそも、この scan は必ず None ではないでしょうか。 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. 最後のnodeで止まっているつもりで書いていた様です...(し、その後stack[-1]をnextにしているしでぐちゃぐちゃですね...)。ありがとうございます。
|
||
reversed = sentinel | ||
|
||
while stack: | ||
reversed.next = stack[-1] | ||
stack.pop() | ||
reversed = reversed.next | ||
|
||
return sentinel.next | ||
``` | ||
- 他の人の回答をみてると全部のnextの情報を繋ぐのをやめてメモリを節約するとMemoryLimitに収まるらしいので書いてみる 。printしてみるとリストの各要素がnextの果てまで記録していて、空間計算量がO(N^2)になっていた様で、全く気づいてなかった。 | ||
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. これは、二重に間違えています。試しに、 reversed.next = None
return sentinel.next というふうに、return の上に一行足してみましょう。これで動くはずです。 そのうえで、もう一回考察してみて下さい。 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. 試してみたら動きました。なるほど...。 print(reversed.next)してみたところ"Error - Found cycle in the ListNode"が表示されました。while文の中でずっとループを作りながら遡っていたから、そこにトラップされてエラーを吐いていたのですね。 「2重」と仰っていたのはこれに加えて、意図した動きをしていたら空間計算量は普通にO(N)だからですね。
も今見るとリストの大きさ分保存されているだけですね(今見るとむしろ何を見てO(N^2)と思ったのか不思議です...。Memory Limit Exceededという語感から空間計算量に問題があるという先入観を持ってしまったのだと思います。)。 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. 理解を一応確認します。最後に pop してきたものの next がその一つ前のやつになっているので、最後の2要素がループになっています。 Memory Limit Exceeded になるのは、おそらく出力を検証している部分が出力をリストに直してから結果を検証しています。そして、そこが無限ループに陥っています。 ここで得られる教訓は、仕事を引き継ぐときに何を引き継いでいるかを意識しようということ、です。 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.
これは理解できておりました。
具体的な検証の仕方のイメージはついておらず、この推測は立っておりませんでした。
ノード1つ分を処理し終えた時にどこまで仕事が終わっているか認識が甘かったために、最後の要素が1つ前の要素を指したままでループを形成してしまったことに気づけなかったものと認識しています。その意味でおっしゃる教訓はキャッチできていると考えています。 |
||
- reversed = stack[-1]をする必要はなくて、reversed = stack.pop()とするだけで消したvalueを返してくれる | ||
|
||
```Python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
scan = head | ||
stack = [] | ||
|
||
while scan: | ||
stack.append(scan) | ||
scan = scan.next | ||
|
||
sentinel = ListNode(0, scan) | ||
reversed = sentinel | ||
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. reversed は built-in と同じ名前なのでできれば避けたいです。 https://discord.com/channels/1084280443945353267/1262761766887358557/1324487835557953546 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. ありがとうございます、last_nodeやprevious_nodeで考えてみます。 |
||
|
||
while stack: | ||
last_node = stack.pop() | ||
reversed.next = ListNode(last_node.val) | ||
reversed = reversed.next | ||
|
||
return sentinel.next | ||
``` | ||
|
||
## Step 2 | ||
### 学んだこと | ||
- List.reverese()で一発で逆順にしてくれる | ||
- Stackを使う方法、再帰を使う方法(https://github.com/goto-untrapped/Arai60/pull/27/files/14646ec0859dd9411e6983bf6c63e6f15a1f9f32#r1638693522)、 切断して繋ぐ方法、後ろから繋いでいく方法があった。後ろから繋いでいく方法が短くて綺麗。こちらの方が一通りやられている: https://github.com/ichika0615/arai60/pull/6/files | ||
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. Memory Limit Exceeded のヒントはこれです。 |
||
|
||
|
||
### 後ろから繋いでいく方法 | ||
```Python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
original_node = head | ||
reversed_node = None | ||
|
||
while original_node: | ||
reversed_node = ListNode(original_node.val, reversed_node) | ||
original_node = original_node.next | ||
|
||
return reversed_node | ||
``` | ||
|
||
### 切断して繋ぎ変えていく方法(reversedとforwardの2つのLinked Listを用意して、headから前進させつつその前の値をreversedに格納) | ||
- While内の1番上はtempに入れてるだけ、2行目が繋ぎ変えの操作、下2行は2つのノードの更新処理 | ||
```Python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
scan = head | ||
reversed = None | ||
|
||
while scan: | ||
scan_next = scan.next | ||
scan.next = reversed | ||
reversed = scan | ||
scan = scan_next | ||
|
||
return reversed | ||
``` | ||
|
||
|
||
## Step 3 | ||
### コメント | ||
- 切断してから繋ぐやり方の理解が怪しい(過去の問題のPRで指摘され中)のでこれで書いてみる | ||
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. |
||
- 2:30, 1:57, 1:55 | ||
|
||
```Python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
scan = head | ||
previous_scan = None | ||
|
||
while scan: | ||
# scan.nextはtempに同じ | ||
scan_next = scan.next | ||
# 実際の仕事(ListNodeをひっくり返す) | ||
scan.next = previous_scan | ||
# 更新 | ||
previous_scan = scan | ||
scan = scan_next | ||
|
||
return previous_scan | ||
``` | ||
|
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.
私も最初、よく考えずにノードをスタックにそのまま格納して書いて、MLEでした。
ノードの値の情報だけ抽出してスタックに格納(->その後取り出しながらnewノードを編んでいく流れ)する方法にシフトしたら、解決しました。