From 48f2749be9c4ec78c6f24c887880e34c7206f678 Mon Sep 17 00:00:00 2001 From: colorbox Date: Thu, 28 Nov 2024 00:13:25 +0900 Subject: [PATCH 1/2] add step1 - 3 --- 387/step1.cpp | 24 +++++++++++++ 387/step2_1.cpp | 23 ++++++++++++ 387/step2_2.cpp | 32 +++++++++++++++++ 387/step2_3.cpp | 43 ++++++++++++++++++++++ 387/step2_4.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ 387/step3.cpp | 15 ++++++++ 6 files changed, 233 insertions(+) create mode 100644 387/step1.cpp create mode 100644 387/step2_1.cpp create mode 100644 387/step2_2.cpp create mode 100644 387/step2_3.cpp create mode 100644 387/step2_4.cpp create mode 100644 387/step3.cpp diff --git a/387/step1.cpp b/387/step1.cpp new file mode 100644 index 0000000..6e8477a --- /dev/null +++ b/387/step1.cpp @@ -0,0 +1,24 @@ +/* +Solve Time: 4:20 + +Time: O(n) +Space: O(1) + +一回の走査で解けないかを軽く模索したが思いつかなかったので愚直にmapで記録し、二回ループする手法で解いた。 +一回の走査で解くことに固執しかけて時間を無駄に思想になっていたため、そこに気づけた点が個人的によかった +*/ +class Solution { + public: + int firstUniqChar(string s) { + map character_to_count; + for (const auto& c : s) { + character_to_count[c]++; + } + for (int i = 0; i < s.size() ; i++) { + if (character_to_count[s[i]] == 1) { + return i; + } + } + return -1; + } +}; diff --git a/387/step2_1.cpp b/387/step2_1.cpp new file mode 100644 index 0000000..b39a2a5 --- /dev/null +++ b/387/step2_1.cpp @@ -0,0 +1,23 @@ +/* +Time: O(n) +Space: O(1) + +step1の改良、マジックナンバーを定数にした +*/ +class Solution { +public: + int firstUniqChar(string s) { + map character_to_count; + for (const auto& c : s) { + character_to_count[c]++; + } + for (int i = 0; i < s.size(); i++) { + if (character_to_count[s[i]] == 1) { + return i; + } + } + + int const kNotFound = -1; + return kNotFound; + } +}; diff --git a/387/step2_2.cpp b/387/step2_2.cpp new file mode 100644 index 0000000..7887038 --- /dev/null +++ b/387/step2_2.cpp @@ -0,0 +1,32 @@ +/* +Time : O(N log N) +Space : O(N) + +https://github.com/kazukiii/leetcode/pull/16/files#diff-f400dc0fa41a78f5b2a9ec5c2d5364dd8cf0da8dc9e8c39d15f52f98ea05394b +を参考にした解法。 +平衡木(mapのkey)を利用して文字の初出インデックスを管理。 +二度目の出現でインデックスを削除することで、平衡木の先頭には一度しか出現していない文字のインデックスが残る。 +3度以上の出現で削除した要素が復帰してしまうが、インデックスが大きいため結果に影響しない。 +*/ +class Solution { +public: + int firstUniqChar(string s) { + map character_to_first_index; + map index_to_character; + for (int i = 0; i < s.size(); i++) { + char c = s[i]; + if (character_to_first_index.contains(c)) { + int first_index = character_to_first_index[c]; + index_to_character.erase(first_index); + continue; + } + character_to_first_index[c] = i; + index_to_character[i] = c; + } + if (index_to_character.empty()) { + const int kNotFound = -1; + return kNotFound; + } + return index_to_character.begin()->first; + } +}; diff --git a/387/step2_3.cpp b/387/step2_3.cpp new file mode 100644 index 0000000..59e5ffa --- /dev/null +++ b/387/step2_3.cpp @@ -0,0 +1,43 @@ +/* +Time : O(N log N) +Space : O(N) + +https://github.com/kazukiii/leetcode/pull/16/files#diff-f5b3276a9df261ed1c1e70d5b6de00ca4544e1a1ae1de6a466add8df5cd3d1b0 +を参考にした解法。 +ソートで文字種ごとに隣接させ、二度以上出現したものを除外し、min比較で最小インデックスを求める。 +*/ +class Solution { +public: + int firstUniqChar(string s) { + vector character_indices; + for (int i = 0; i < s.size(); i++) { + character_indices.push_back({s[i], i}); + } + sort(character_indices.begin(), character_indices.end()); + int count = 1; + int first_unique_character_index = numeric_limits::max(); + for (int i = 0; i < s.size(); i++) { + if (i < s.size() - 1 && character_indices[i].character == character_indices[i + 1].character) { + count++; + continue; + } + if (count == 1) { + first_unique_character_index = min(first_unique_character_index, character_indices[i].index); + } + count = 1; + } + if (first_unique_character_index == numeric_limits::max()) { + return -1; + } + return first_unique_character_index; + } + + struct CharacterIndex { + char character; + int index; + + bool operator<(const CharacterIndex& other) { + return character < other.character; + } + }; +}; diff --git a/387/step2_4.cpp b/387/step2_4.cpp new file mode 100644 index 0000000..d3b058d --- /dev/null +++ b/387/step2_4.cpp @@ -0,0 +1,96 @@ +/* +Time : O(N) +Space : O(1) + +LRUを応用してできるとのことだったので実装。 +https://www.geeksforgeeks.org/lru-cache-implementation-using-double-linked-lists/ +本質的に平衡木による解法と大差ない気がする。 +*/ +struct Node { + int index; + int count; + Node* prev; + Node* next; + + explicit Node(int i) { + index = i; + count = 1; + prev = nullptr; + next = nullptr; + } +}; + +class LRUCache { + public: + Node* head; + Node* tail; + map character_to_node; + + LRUCache() { + head = new Node(numeric_limits::max()); + tail = new Node(numeric_limits::max()); + head->next = tail; + tail->prev = head; + } + + ~LRUCache() { + for (auto [_c, node] : character_to_node) { + delete node; + } + delete head; + delete tail; + } + + void Put(char character, int index) { + if (character_to_node.contains(character)) { + Node *node = character_to_node[character]; + Remove(node); + node->count++; + return; + } + + Node *node = new Node(index); + character_to_node[character] = node; + PushBack(node); + } + + bool Empty() { + return head->next->index == tail->index; + } + + private: + void Remove(Node* node) { + if (node->prev == nullptr) { + return; + } + Node* prev = node->prev; + Node* next = node->next; + prev->next = next; + next->prev = prev; + node->prev = nullptr; + node->next = nullptr; + } + + void PushBack(Node* node) { + Node* prev = tail->prev; + prev->next = node; + node->prev = prev; + node->next = tail; + tail->prev = node; + } +}; + +class Solution { + public: + int firstUniqChar(string s) { + LRUCache cache = LRUCache(); + for (int i = 0; i < s.size(); i++) { + cache.Put(s[i], i); + } + if (cache.Empty() || cache.head->next->count > 1) { + return -1; + } + return cache.head->next->index; + } +}; + diff --git a/387/step3.cpp b/387/step3.cpp new file mode 100644 index 0000000..e426a98 --- /dev/null +++ b/387/step3.cpp @@ -0,0 +1,15 @@ +class Solution { +public: + int firstUniqChar(string s) { + map character_to_count; + for (const char& c : s) { + character_to_count[c]++; + } + for (int i = 0; i < s.size(); i++) { + if (character_to_count[s[i]] == 1) { + return i; + } + } + return -1; + } +}; From 1fdb87356938b312be64bae5583e0095d0bd3530 Mon Sep 17 00:00:00 2001 From: colorbox Date: Sat, 30 Nov 2024 17:42:03 +0900 Subject: [PATCH 2/2] add queue and map solve --- 387/step2_2_suggested.cpp | 34 +++++++++++++++++++++++++++++++++ 387/step2_2_suggested_fixed.cpp | 31 ++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 387/step2_2_suggested.cpp create mode 100644 387/step2_2_suggested_fixed.cpp diff --git a/387/step2_2_suggested.cpp b/387/step2_2_suggested.cpp new file mode 100644 index 0000000..efee2fc --- /dev/null +++ b/387/step2_2_suggested.cpp @@ -0,0 +1,34 @@ +/* +https://github.com/colorbox/leetcode/pull/29#discussion_r1861430039 +を見てそれを参考に自分で書いた解法、比較用 +*/ +class Solution { + public: + int firstUniqChar(string s) { + queue queue; + map character_to_count; + for (int i = 0; i < s.size(); i++) { + char c = s[i]; + character_to_count[c]++; + queue.push({c, i}); + while (true) { + char front_character = queue.front().character; + if (character_to_count[front_character] > 1) { + queue.pop(); + } else { + break; + } + } + } + if (queue.empty()) { + return -1; + } + return queue.front().index; + } + + private: + struct CharacterAndCount { + char character; + int index; + }; +}; diff --git a/387/step2_2_suggested_fixed.cpp b/387/step2_2_suggested_fixed.cpp new file mode 100644 index 0000000..e1f83ca --- /dev/null +++ b/387/step2_2_suggested_fixed.cpp @@ -0,0 +1,31 @@ +/* +step2_2_suggested.cpp +を +https://github.com/colorbox/leetcode/pull/29#discussion_r1861430039 +の書き方に沿って修正したコード、参照用 +*/ +class Solution { + public: + int firstUniqChar(string s) { + queue characters; + map character_to_count; + for (int i = 0; i < s.size(); ++i) { + char c = s[i]; + ++character_to_count[c]; + characters.push({c, i}); + while (character_to_count[characters.front().character] >= 2) { + characters.pop(); + } + } + if (characters.empty()) { + return -1; + } + return characters.front().index; + } + + private: + struct CharacterAndCount { + char character; + int index; + }; +};