diff --git a/92.ReverseLinkedListII/memo.md b/92.ReverseLinkedListII/memo.md new file mode 100644 index 0000000..87bf66b --- /dev/null +++ b/92.ReverseLinkedListII/memo.md @@ -0,0 +1,35 @@ +## ステップ1 +一旦全てのnodeを分解して、つなぎ合わせる。 +1からスタートするindexとnodeをmap内に記録して下記の3段階で繋げる。 +・leftまでは昇順 +・left ~ rightは降順 +・rightの次から、最後までは昇順 +時間計算量O(n) +空間計算量O(n) + +## ステップ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スペックだと空間計算量に対してそこまでシビアになる必要がないと聞くこともあるので +mapやstackに入れて管理した方が読みやすいと感じた。 + +## ステップ3 +**3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** + + diff --git a/92.ReverseLinkedListII/step1.cpp b/92.ReverseLinkedListII/step1.cpp new file mode 100644 index 0000000..0b57e09 --- /dev/null +++ b/92.ReverseLinkedListII/step1.cpp @@ -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; + map index_to_node; + auto node = head; + while (node) { + index_to_node[node_count] = node; + node_count++; + node = node->next; + } + + ListNode dummy_head; + node = &dummy_head; + + int current_index = 1; + 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; + } + }; diff --git a/92.ReverseLinkedListII/step2_1.cpp b/92.ReverseLinkedListII/step2_1.cpp new file mode 100644 index 0000000..194e28c --- /dev/null +++ b/92.ReverseLinkedListII/step2_1.cpp @@ -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 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; + } + }; diff --git a/92.ReverseLinkedListII/step2_2.cpp b/92.ReverseLinkedListII/step2_2.cpp new file mode 100644 index 0000000..4745667 --- /dev/null +++ b/92.ReverseLinkedListII/step2_2.cpp @@ -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 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; + } +}; diff --git a/92.ReverseLinkedListII/step2_3.cpp b/92.ReverseLinkedListII/step2_3.cpp new file mode 100644 index 0000000..9d58cf9 --- /dev/null +++ b/92.ReverseLinkedListII/step2_3.cpp @@ -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; + } + return dummy_head.next; + } +}; diff --git a/92.ReverseLinkedListII/step3.cpp b/92.ReverseLinkedListII/step3.cpp new file mode 100644 index 0000000..40bb0a4 --- /dev/null +++ b/92.ReverseLinkedListII/step3.cpp @@ -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 index_to_node; + ListNode* node = head; + while (node) { + index_to_node[num_nodes] = node; + num_nodes++; + 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; + } + };