-
Notifications
You must be signed in to change notification settings - Fork 0
92. Reverse Linked List II #65
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,35 @@ | ||
| ## ステップ1 | ||
| 一旦全てのnodeを分解して、つなぎ合わせる。 | ||
| 1からスタートするindexとnodeをmap内に記録して下記の3段階で繋げる。 | ||
| ・leftまでは昇順 | ||
| ・left ~ rightは降順 | ||
| ・rightの次から、最後までは昇順 | ||
|
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. 昇順かどうかの制約ってありましたっけ?
Owner
Author
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に含まれるnode全てにindexを付与して新たにリストを作るイメージにしました。 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. ありがとうございます。 |
||
| 時間計算量O(n) | ||
| 空間計算量O(n) | ||
|
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. 追加の空間計算量 O(1) で実装することはできますか? |
||
|
|
||
| ## ステップ2 | ||
| step2_1.cpp | ||
| step1に変数名の変更とコメントを追加したもの。 | ||
|
|
||
| step2_2.cpp | ||
| stackを使った解法。 | ||
| step2_1のmapを使った解法との違いは、left ~ right の部分だけをstackに保存し、 | ||
| 元のつながりを維持しながら反転部分だけつなぎ直している。 | ||
| 時間計算量O(n) | ||
| 空間計算量O(n) | ||
| 空間計算量は同じでもleft ~ rightが小さいとこちらの方が効率的か。 | ||
|
|
||
| step2_3.cpp | ||
| step2_2のstackを使っている解法から直接nodeをつなぎ合わす方式に変更したもの | ||
| 時間計算量O(n) | ||
| 空間計算量O(1) | ||
| mapやstackを使わないので改善されているか | ||
|
|
||
| 一つのループ内でnodeが3種類出てくるので処理を追うのが少し大変 | ||
| 近年のPCスペックだと空間計算量に対してそこまでシビアになる必要がないと聞くこともあるので | ||
|
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. これはそうだと思います。 (出題意図に繋ぎ変えのお手玉ができるかはありそうですが。) |
||
| mapやstackに入れて管理した方が読みやすいと感じた。 | ||
|
|
||
| ## ステップ3 | ||
| **3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * struct ListNode { | ||
| * int val; | ||
| * ListNode *next; | ||
| * ListNode() : val(0), next(nullptr) {} | ||
| * ListNode(int x) : val(x), next(nullptr) {} | ||
| * ListNode(int x, ListNode *next) : val(x), next(next) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| ListNode* reverseBetween(ListNode* head, int left, int right) { | ||
| if (!head) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int node_count = 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. node_countをindex_to_nodeという名前のmapに入れて検索していると思うので、この変数はnode_indexみたいな名前の方が対応があるのかな、と思いました |
||
| map<int, ListNode*> index_to_node; | ||
|
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. indexは1から順に並ぶので、mapじゃなくて配列でも同様のことができると思いました |
||
| auto node = head; | ||
|
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. auto型は、どのような時に使うのか教えていただきたいです! |
||
| while (node) { | ||
| index_to_node[node_count] = node; | ||
| node_count++; | ||
| node = node->next; | ||
| } | ||
|
|
||
| ListNode dummy_head; | ||
| node = &dummy_head; | ||
|
|
||
| int current_index = 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. current_index の意味は「今見ているノードの次のindex」という感じですかね?(nodeがdummyからスタートしているので)その意味だとcurrentとついているのは少し違和感がありました |
||
| while (current_index < left) { | ||
| node->next = index_to_node[current_index]; | ||
| current_index++; | ||
| node = node->next; | ||
| } | ||
|
|
||
| current_index = right; | ||
| while (current_index >= left) { | ||
| node->next = index_to_node[current_index]; | ||
| current_index--; | ||
| node = node->next; | ||
| } | ||
|
|
||
| current_index = right + 1; | ||
| while (current_index < node_count) { | ||
| node->next = index_to_node[current_index]; | ||
| current_index++; | ||
| node = node->next; | ||
| } | ||
| node->next = nullptr; | ||
|
|
||
| return dummy_head.next; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * struct ListNode { | ||
| * int val; | ||
| * ListNode *next; | ||
| * ListNode() : val(0), next(nullptr) {} | ||
| * ListNode(int x) : val(x), next(nullptr) {} | ||
| * ListNode(int x, ListNode *next) : val(x), next(next) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| ListNode* reverseBetween(ListNode* head, int left, int right) { | ||
| if (!head) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int num_nodes = 1; | ||
| map<int, ListNode*> index_to_node; | ||
| auto node = head; | ||
| while (node) { | ||
| index_to_node[num_nodes] = node; | ||
| num_nodes++; | ||
| node = node->next; | ||
| } | ||
|
|
||
| ListNode dummy_head; | ||
| node = &dummy_head; | ||
|
|
||
| // leftまでを昇順に繋げる | ||
| int index = 1; | ||
| while (index < left) { | ||
| node->next = index_to_node[index]; | ||
| index++; | ||
| node = node->next; | ||
| } | ||
|
|
||
| // left ~ rightは降順に繋げる | ||
| index = right; | ||
| while (index >= left) { | ||
| node->next = index_to_node[index]; | ||
| index--; | ||
| node = node->next; | ||
| } | ||
|
|
||
| // right + 1 から最後までは昇順に繋げる | ||
| index = right + 1; | ||
| while (index < num_nodes) { | ||
| node->next = index_to_node[index]; | ||
| index++; | ||
| node = node->next; | ||
| } | ||
| node->next = nullptr; | ||
|
|
||
| return dummy_head.next; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * struct ListNode { | ||
| * int val; | ||
| * ListNode *next; | ||
| * ListNode() : val(0), next(nullptr) {} | ||
| * ListNode(int x) : val(x), next(nullptr) {} | ||
| * ListNode(int x, ListNode *next) : val(x), next(next) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| ListNode* reverseBetween(ListNode* head, int left, int right) { | ||
| if (!head) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| ListNode dummy_head; | ||
| dummy_head.next = head; | ||
| ListNode* node = &dummy_head; | ||
|
|
||
| // 探索中のnodeをleftの直前まで移動 | ||
| for (int i = 0; i < left - 1; i++) { | ||
| node = node->next; | ||
| } | ||
|
|
||
| // leftからrightの間を逆順に繋ぐため直前のnodeを記録 | ||
| ListNode* prev_left = node; | ||
|
|
||
| // 探索中のnodeをleftの位置へ移動 | ||
| node = node->next; | ||
| stack<ListNode*> reversed_nodes; | ||
| for (int i = left; i <= right; i++) { | ||
| reversed_nodes.push(node); | ||
| node = node->next; | ||
| } | ||
|
|
||
| // right + 1にあるnodeを記録 | ||
| ListNode* current_node = node; | ||
| while (!reversed_nodes.empty()) { | ||
| prev_left->next = reversed_nodes.top(); | ||
| prev_left = prev_left->next; | ||
| reversed_nodes.pop(); | ||
| } | ||
|
|
||
| prev_left->next = current_node; | ||
|
|
||
| return dummy_head.next; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * struct ListNode { | ||
| * int val; | ||
| * ListNode *next; | ||
| * ListNode() : val(0), next(nullptr) {} | ||
| * ListNode(int x) : val(x), next(nullptr) {} | ||
| * ListNode(int x, ListNode *next) : val(x), next(next) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| ListNode* reverseBetween(ListNode* head, int left, int right) { | ||
| if (!head) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| ListNode dummy_head; | ||
| dummy_head.next = head; | ||
| ListNode* node = &dummy_head; | ||
|
|
||
| // 探索中のnodeをleftの直前まで移動 | ||
| for (int i = 0; i < left - 1; i++) { | ||
| node = node->next; | ||
| } | ||
|
|
||
| // leftの位置のnode | ||
| ListNode* reversed = node->next; | ||
|
|
||
| for (int i = left; i < right; i++) { | ||
| // reversedの次を取り出し、reversedの次に、次の次のnodeを繋げることで | ||
| // 取り出したnodeを一時的にリストから外す | ||
| ListNode* next_node = reversed->next; | ||
| reversed->next = next_node->next; | ||
| // 初回はnode->nextはleftの先頭にいる | ||
| next_node->next = node->next; | ||
| node->next = next_node; | ||
|
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の役割が変わるのが気になりました。 (繋ぎ方が複数あるみたいなのでイメージと違っていたらすみません) |
||
| } | ||
| return dummy_head.next; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * struct ListNode { | ||
| * int val; | ||
| * ListNode *next; | ||
| * ListNode() : val(0), next(nullptr) {} | ||
| * ListNode(int x) : val(x), next(nullptr) {} | ||
| * ListNode(int x, ListNode *next) : val(x), next(next) {} | ||
| * }; | ||
| */ | ||
| class Solution { | ||
| public: | ||
| ListNode* reverseBetween(ListNode* head, int left, int right) { | ||
| if (!head) { | ||
| return nullptr; | ||
| } | ||
|
|
||
| int num_nodes = 1; | ||
| map<int, ListNode*> index_to_node; | ||
| ListNode* node = head; | ||
| while (node) { | ||
| index_to_node[num_nodes] = node; | ||
| num_nodes++; | ||
|
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. num_nodesだとnode全体の数という感じがしました。 |
||
| node = node->next; | ||
| } | ||
|
|
||
| ListNode dummy_head; | ||
| node = &dummy_head; | ||
|
|
||
| int index = 1; | ||
| while (index < left) { | ||
| node->next = index_to_node[index]; | ||
| index++; | ||
| node = node->next; | ||
| } | ||
|
|
||
| index = right; | ||
| while (index >= left) { | ||
| node->next = index_to_node[index]; | ||
| index--; | ||
| node = node->next; | ||
| } | ||
|
|
||
| index = right + 1; | ||
| while (index < num_nodes) { | ||
| node->next = index_to_node[index]; | ||
| index++; | ||
| node = node->next; | ||
| } | ||
| node->next = nullptr; | ||
|
|
||
| return dummy_head.next; | ||
| } | ||
| }; | ||
|
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ではだめなのだろうかと思いましたが、読みやすいです。 |
||
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.
ノードの繋ぎ直す順番を管理して、その順番通りに繋ぎ直すという手法が分かりやすくて参考になりました!