Skip to content
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
68 changes: 68 additions & 0 deletions 206_reverse_linked_list/answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
問題:https://leetcode.com/problems/reverse-linked-list/description/

## step1

まあ前回に引き続きスタックだからとりあえず全部の->valをpushして走査したら取り出してheadからのリストノードの値を入れ替えてみる。
```cpp
class Solution {
public:
ListNode* reverseList(ListNode* head) {
stack<int> valstack;
ListNode* dummy = new ListNode(2147483647,head);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

どうして値を2147483647にしましたか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

コメントありがとうございます。
int型のmax valueを番兵に用いています。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

どうして0や他の値ではなく、INT_MAXを値として選びましたか?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dummyノードの値は一度も使用していないので、番兵(コードを簡略化するための値)としての役割はなさそうです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ご返信ありがとうございます。
その通りです。この場合headを保存しておけばよいだけですね。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

わざわざ2147483647と書いて、(環境依存になる)intの最大値を選んだ理由はありますか?仮にINT_MAXが必要だったとしても、リテラルで書くのは好ましくないように思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dummyの役割は何でしょうか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

先頭のポインタを保存しておくために使ったのですが、別に番兵でなくてもよいですね。
気づいていませんでした。ありがとうございます。

while (head) {
valstack.push(head->val);
head = head->next;
}
ListNode *temp = dummy->next;
while (!valstack.empty()) {
temp->val = valstack.top();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ListNodeの値を書き換えるのは、明示的に言及されていないものの、問題の意図から外れるかもしれません。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

new演算子に使いなれておらず、無意識にこのような選択をしました。
逆転した新しいノードという題意からしても破壊的なコードは避けるべきですね。ありがとうございます。

Copy link
Copy Markdown

@liquo-rice liquo-rice May 8, 2026

Choose a reason for hiding this comment

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

明示的に書かれていないのですが、ListNodeのnextのみを書き換えるのが、この問題の意図かと思います。

Given the head of a singly linked list, reverse the list, and return the reversed list.

問題に「新しいノード」とは書いていませんね。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

なるほど、本筋は再帰やループによるnext書き換えであってvalの書き換えと新たなリストの作成は意図からずれるということですね。
読み取れていませんでした。ありがとうございます。

valstack.pop();
temp = temp->next;
}
return dummy->next;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dummyのメモリを解放していないので、メモリリークしています。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

メモリリークしないようにするにはどうすれば良さそうでしょうか?

}
};
```
これでaccept。計算量はどちらもO(n)。

## step2

他の方のコード、コメント集を見た。再帰の方法もあるがO(n)。
参考:https://discord.com/channels/1084280443945353267/1231966485610758196/1239417493211320382

```cpp
class Solution {
private:
ListNode* recursion(ListNode* head) {
if (!head || !head->next) {
return head;
}
else {
ListNode* newhead = recursion(head->next);
head->next->next = head;
head->next = nullptr;
return newhead;
}
}
```

特にこの方の空間計算量O(1)での方法は参考になった。
参考:https://github.com/attractal/leetcode/pull/7/changes#diff-4066faf067589a38d6fd384b7a41db69f3320f5699ad178f6a6df82904e85333R39

```cpp
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* previous = nullptr;
ListNode* node = head;
while (node != nullptr) {
ListNode* next_node = node->next;
node->next = previous;
previous = node;
node = next_node;
}
return previous;
}
};
```
再帰では始めに一番最後のノードが返されるところから最初のノードにまで遡っていくが、この方法ではprevious=nullとするイニシャルコストを払うことで最初から最後まで直線的に処理が行える。
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

この方法ではprevious=nullとするイニシャルコストを払う

ここで「イニシャルコスト」はどういう意味で使っていますか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ループの中にnullptrを繋げる処理を書かずにループの外側で最初のノードにのみnullptrを繋げる処理を行うという意味で使っています。
ループ内をキレイにするために外側で少しキレイじゃないことをするというようなニュアンスでこの表現になりました。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ループの中にnullptrを繋げる処理を書かずにループの外側で最初のノードにのみnullptrを繋げる処理を行う

これはコードと振る舞いが違いませんか?単にpreviousをnullptrで初期化しているように見えます。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

再帰で書いたときに毎回nullptrを代入していたことと比較しての説明です。
ループのスタート地点にnullptrとheadを前後の位置関係で与えているだけなのでループの外というのは違うかもしれません。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

意図は理解しましたが、単にpreviousをnullptrで初期化することを「キレイじゃない」と言うことに違和感があります。イニシャルコストという表現も、重い処理が最初に走るようなイメージがあります。