-
Notifications
You must be signed in to change notification settings - Fork 0
Reverse Linked List #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,203 @@ | ||
# Reverse Linked List | ||
|
||
## step1 | ||
|
||
- 問題を整理する | ||
- リンクドリストが与えられるので逆にして返せ | ||
- 手でやるならどうやるか | ||
- 前から読んでってvalをstackに書いておく | ||
- 最後まで読み終わったらstackの後ろからvalを取り出してLinked Listを繋げていく | ||
- コードで書いてみる | ||
- 5分ほどで解けた | ||
- 最初に書いたとき`while node.next is not None:`としてしまった | ||
- nodeの次がなくなったら次に進めないなという感覚があったから | ||
- 実際はnode.next is Noneでストップしてしまうと最後の要素をカウントできない | ||
|
||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
if head is None: | ||
return None | ||
|
||
stack = list() | ||
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. 質問ですが、listを[]ではなく、list()として定義した意図はありますか? 自分も気になって調べましたが、 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. たしか辞書の初期化も dict() より = {} の方が推奨と聞いたことがあります |
||
node = head | ||
|
||
while node is not None: | ||
stack.append(node.val) | ||
node = node.next | ||
|
||
dummy = ListNode(-1) | ||
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. スタックから初期ノードを持ってくれば、ダミーが不要になってコードがシンプルになりそうですね 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. 確かにそうですね、思いつきませんでした。ありがとうございます。 |
||
reverse_node = dummy | ||
|
||
while stack: | ||
val = stack.pop() | ||
next_node = ListNode(val) | ||
reverse_node.next = next_node | ||
reverse_node = reverse_node.next | ||
|
||
return dummy.next | ||
``` | ||
|
||
## step2 他の人の解法を見る・自分の修正 | ||
|
||
|
||
### [tarinaiさん](https://github.com/tarinaihitori/leetcode/pull/6/files/7ae6c941f485e4fd52fab64cf17584150ea87d03#diff-f1530fc1072ee1f0b7de99a2e5236992c72355da69982c8ca516fcfba7c57927) | ||
- リストを読んでるときに逆向きにつけ直している | ||
- こっちの方が一周で終わるから早い | ||
- 自分のやり方と考え方から違って面白い | ||
- currentとpreviousという名前の付け方について議論している | ||
- [ここ](https://github.com/colorbox/leetcode/pull/22#discussion_r1694239660)でも | ||
- 今のと前のは確かに違和感がある | ||
- reversed と not reversedのように操作を終えたもの、操作前のもののような名付けは直感に合う | ||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
current = head | ||
previous = None | ||
while current: | ||
next_temp = current.next | ||
current.next = previous | ||
previous = current | ||
current = next_temp | ||
return previous | ||
``` | ||
|
||
### 再帰 | ||
|
||
- 再帰でもできるらしいので自分で考えてみる | ||
- 再帰で考えたことがないのでどのようなところから取り組めばいいのかわからない | ||
- 手でやる場合 | ||
- 一つのリンクドリストに一人が担当しているとする | ||
- 前の人から信号を後ろの人に渡す | ||
- 後ろの人がいなかったらリンクを逆向きにして前に返す | ||
- 後ろの人から信号が来たらリンクを逆にして前に返す | ||
- よくわからないので他の人の回答を見てそれを解釈する | ||
|
||
- 解釈 | ||
|
||
```python | ||
class Solution: | ||
# leetcodeはデフォルトの再帰の深さの最大数が55,000のため、今回の制約(最大5,000)だとRecursionErrorは考慮しなくて良い | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
def _reverse_linked_list(head, previous): | ||
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. inner function の名前を _ で始めることは少ないように思います。 _ で始めるのは、メンバ関数のうち non-public なものが多いと思います。
|
||
# head = 次に処理するnode | ||
# previous = すでに処理したnode | ||
if head is None: | ||
return previous | ||
# 次に処理するnodeがなくなっていればすでに処理したnodeを返す | ||
temp = head.next | ||
# 次に処理するnodeの次のnodeを取得する | ||
head.next = previous | ||
# head.nextをすでに処理したnodeに繋げる | ||
return _reverse_linked_list(temp, head) | ||
# tempを次に処理するnode、headをすでに処理したnodeとして次の操作に移行する | ||
return _reverse_linked_list(head, None) | ||
# 一番最初は次に処理するのはheadですでに処理したnodeは存在しない | ||
``` | ||
- 仕組みはわかったがどうやったらこの再帰を思いつけるだろう | ||
- 手でやるなら | ||
- 何人かで鎖のようなものを繋ぎかえる | ||
- 前の人からは繋ぎかえたもの最後と繋ぎかえてないものの先頭を渡される | ||
- 繋ぎかえてないものの先頭を外して、繋ぎかえたものの最後に繋げる | ||
- 次の人に渡す | ||
- 繋ぎかえてないものがなくなったら繋ぎかえたものを返す | ||
- RecursionErrorとは | ||
- 再帰が深すぎる時に起きるエラー | ||
- [sys.setrecursionlimit()](https://docs.python.org/3/library/sys.html#sys.setrecursionlimit)で変更できる | ||
|
||
```python | ||
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 | ||
head.next = None | ||
# 繋いでる向きを反対にする | ||
return new_head | ||
``` | ||
- 手でやるなら | ||
- 何人かで鎖のようなものを繋ぎかえる | ||
- 最初に鎖の担当する箇所を決める | ||
- 担当箇所が鎖の最後ならそれを前の人に戻す | ||
- 戻されたら自分の箇所を逆向きにつなぐ | ||
- 鎖の最後の部分を前の人に戻す | ||
- この時自分の操作した部分は最後の部分に連なっている | ||
- 最初の人まで戻ってきたら最初の向きを繋ぎかえて鎖の最後を返す | ||
- わかりにくい説明になってしまった。 | ||
- 鎖全体のheadと自分の担当箇所のheadが存在するが同じ単語で表されているところがコードの難しさに繋がっている気がする | ||
- わかりやすいように変えると次のようになるか? | ||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
def reverseListHelper(previous): | ||
if previous is None or previous.next is None: | ||
return previous | ||
|
||
last_node = reverseListHelper(previous.next) | ||
|
||
previous.next.next = previous | ||
previous.next = None | ||
return last_node | ||
|
||
return reverseListHelper(head) | ||
``` | ||
|
||
[Odaさんの再帰の考え方](https://discord.com/channels/1084280443945353267/1231966485610758196/1239417493211320382) | ||
>再帰というのは、リストの頭を担当する部下が、何かを下流にお願いして、仕事が返ってきて、自分も何かをすると、全体のリストが逆順になるというものです。 | ||
>下流に、自分よりも下流の部分を逆順にしろ、といって、したよ。といって、ぽいっと渡されても困りますね。その時に、自分が効率的に仕事をするために何を教えてほしいですか。 | ||
|
||
- 効率的に仕事をするには何を教えて欲しいかという視点を持っておきたい | ||
|
||
### 自分の修正 | ||
|
||
- stackを使うより一周しながらリンクを繋ぎ直す方がわかりやすいと思ったのでそちらでやる | ||
- 自分で書いてみるとnext_tempが思いつきづらいと思った | ||
|
||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
reversed = None | ||
not_reversed = head | ||
|
||
while not_reversed: | ||
next_temp = not_reversed.next | ||
not_reversed.next = reversed | ||
|
||
reversed = not_reversed | ||
not_reversed = next_temp | ||
Comment on lines
+164
to
+169
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. next_tempが思いつきづらいとありましたが、 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. その考え方はなかったのでアドバイス頂けてありがたいです。 |
||
|
||
return reversed | ||
``` | ||
|
||
`while not_reversed` ではなく`while not_reversed is not None`と書くべきなのでは? | ||
|
||
- is not None について | ||
- Googleは[Always use "is None"(or "is not None")](https://google.github.io/styleguide/pyguide.html#2144-decision)と言っている | ||
- pep8は[beware of writing](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) | ||
- [型ヒントからわかる場合は省略しても良いかもしれない](https://github.com/h1rosaka/arai60/pull/5/files/bc2027b5d4f57992bbe8afb6924f3cf95e591cc3#r1716372910) | ||
- if a: だと 0や何らかの空集合にもFalseと反応するから注意しろというのが本質 | ||
- Google は大規模に開発しているからここらへん細かいのかも? | ||
- 変わらない悩みなの面白い | ||
- [stack overflow](https://stackoverflow.com/questions/7816363/if-a-vs-if-a-is-not-none) | ||
- [Reddit](https://www.reddit.com/r/learnpython/comments/of5s8i/whats_the_most_pythonic_way_of_checking_if/) | ||
- 今回は 読みやすさ優先で while not_reversedを使います。 | ||
## step3 | ||
三回連続で書いた | ||
step3最後のものと同じ。 | ||
|
||
```python | ||
class Solution: | ||
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
reversed = 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. reversedはbuiltin functionにあるので命名としては避けるのが無難かなと思います。 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. biltinは関数ですが僕が定義したのは変数なので使っても良いのではないかと思って使ってしまいました。 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(type(reversed))
reversed = 5
print(type(reversed)) 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. あまり詳しくないですが、local name spaceにおいては 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. プログラムが動くか動かないかという意味で大丈夫か大丈夫ではないかというと大丈夫です。keyword はだめです。(keyword 一覧確認しておきましょう。) ただ、builtin も後々の書き換えでそれを使いたい人が現れると混乱させるので、書き慣れた人は避けるでしょう。(builtin 一覧も確認しておきましょう。) 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. なるほど、ありがとうございます。確認してみたいと思います。 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. 公式ドキュメントを探して下のように貼り付けるまでを、習慣にするといいでしょう。 専門家の振る舞いとして、読んで調べるのは大事です。 |
||
not_reversed = head | ||
|
||
while not_reversed: | ||
next_temp = not_reversed.next | ||
not_reversed.next = reversed | ||
|
||
reversed = not_reversed | ||
not_reversed = next_temp | ||
|
||
return reversed |
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.
headを特別扱いしなくても良さそうです
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.
確かにその通りです。
あまり考えずにとりあえずという感じで書いていました。