diff --git a/01-15/4.First-Unique-Character-in-a-String/1.cpp b/01-15/4.First-Unique-Character-in-a-String/1.cpp new file mode 100644 index 0000000..dd5d089 --- /dev/null +++ b/01-15/4.First-Unique-Character-in-a-String/1.cpp @@ -0,0 +1,43 @@ +#if __has_include("../debug.hpp") +#include "../debug.hpp" +#endif +// ここまでローカルでのデバッグ用なので気にしないでください -------------------- + +#include + +using namespace std; + +// <時間> +// 18分 +// <感想> +// 一周回って変なことしてしまったと思う +// 原因があるとすれば、O(2N)=O(N)を体で理解していないこと? +// それでも実行時間は早いかなと思ったら全然早くなかった +// 可能性があるとすればO(N)かかる方のif文の分岐かな +// 反省のために残しておく + +// なお以下で出てくるコメントはプロダクト版にも書くつもりのコメント +class Solution { + public: + int firstUniqChar(string s) { + vector indexes(26, -1); + vector is_repeated(26); + for (int i = 0; i < s.size(); ++i) { + auto alpha = s[i] - 'a'; + if (indexes[alpha] == -1) { + indexes[alpha] = i; + } else { + is_repeated[alpha] = true; + } + } + + int min_index = s.size(); + for (int alpha = 0; alpha < 26; ++alpha) { + if (indexes[alpha] != -1 && !is_repeated[alpha]) { + min_index = min(min_index, indexes[alpha]); + } + } + + return min_index != s.size() ? min_index : -1; + } +}; diff --git a/01-15/4.First-Unique-Character-in-a-String/2.cpp b/01-15/4.First-Unique-Character-in-a-String/2.cpp new file mode 100644 index 0000000..36807d2 --- /dev/null +++ b/01-15/4.First-Unique-Character-in-a-String/2.cpp @@ -0,0 +1,29 @@ +#if __has_include("../debug.hpp") +#include "../debug.hpp" +#endif +// ここまでローカルでのデバッグ用なので気にしないでください -------------------- + +#include + +using namespace std; + +// <時間> +// 1分 +// <疑問・不安点(・個人的な感想、違う意見があれば教えてほしいもの)> +// - s[i] - 'a'が初見で伝わるのか問題 +// - countsの他の命名候補としてalpha_countsがあった + +// なお以下で出てくるコメントはプロダクト版にも書くつもりのコメント +class Solution { + public: + int firstUniqChar(string s) { + vector counts(26); + for (int i = 0; i < s.size(); ++i) { + ++counts[s[i] - 'a']; + } + for (int i = 0; i < s.size(); ++i) { + if (counts[s[i] - 'a'] == 1) return i; + } + return -1; + } +}; diff --git a/01-15/4.First-Unique-Character-in-a-String/3.cpp b/01-15/4.First-Unique-Character-in-a-String/3.cpp new file mode 100644 index 0000000..ad76aa6 --- /dev/null +++ b/01-15/4.First-Unique-Character-in-a-String/3.cpp @@ -0,0 +1,26 @@ +#if __has_include("../../debug.hpp") +#include "../../debug.hpp" +#endif +// ここまでローカルでのデバッグ用なので気にしないでください -------------------- + +#include + +using namespace std; + +// <時間> +// 1分 +// <疑問・不安点(・個人的な感想、違う意見があれば教えてほしいもの)> +class Solution { + public: + int firstUniqChar(string s) { + int alphabet_to_count[26]; + fill(alphabet_to_count, alphabet_to_count + 26, 0); + for (auto c : s) { + ++alphabet_to_count[c - 'a']; + } + for (int i = 0; i < s.size(); ++i) { + if (alphabet_to_count[s[i] - 'a'] == 1) return i; + } + return -1; + } +}; diff --git a/01-15/4.First-Unique-Character-in-a-String/Ex1.cpp b/01-15/4.First-Unique-Character-in-a-String/Ex1.cpp new file mode 100644 index 0000000..4a18f17 --- /dev/null +++ b/01-15/4.First-Unique-Character-in-a-String/Ex1.cpp @@ -0,0 +1,75 @@ +#include +#if __has_include("../debug.hpp") +#include "../debug.hpp" +#endif +// ここまでローカルでのデバッグ用なので気にしないでください -------------------- + +#include + +using namespace std; + +// こちらは番外編です。入力がstreamだったときです。 +// <時間> +// Ex2も併せて13分 +// <疑問・不安点(・個人的な感想、違う意見があれば教えてほしいもの)> +// - 2バージョン作っている。 +// Ex2の方がメモリもコード量も少なくて好きなのだが、アクロバティックなので +// 可読性大丈夫かな…と思って無印の方も残している。 +// なお、intの代わりにsize_tを使えばフラグと値の範囲が実際被ることはない。 +// string::nposだってstatic_cast(-1)である。 + +// なお以下で出てくるコメントはプロダクト版にも書くつもりのコメント +class SolutionStream { + public: + SolutionStream() : is_repeated(26), last_indexes(26, -1), index(0) {} + + int firstUniqChar(char c) { + int alpha = c - 'a'; + if (last_indexes[alpha] == -1) { + last_indexes[alpha] = index; + } else { + is_repeated[alpha] = true; + } + + int min_index = INT_MAX; + for (int alpha = 0; alpha < 26; ++alpha) { + if (last_indexes[alpha] != -1 && !is_repeated[alpha]) { + min_index = min(min_index, last_indexes[alpha]); + } + } + + return min_index != INT_MAX ? min_index : -1; + } + + private: + vector is_repeated; + vector last_indexes; + int index; +}; + +class SolutionStream2 { + public: + SolutionStream2() : first_index_or_repeated(26, kNotUsed), index(0) {} + + int firstUniqChar(char c) { + int alpha = c - 'a'; + if (first_index_or_repeated[alpha] == kNotUsed) { + first_index_or_repeated[alpha] = index; + } else { + first_index_or_repeated[alpha] = kRepeated; + } + ++index; + + auto first_index = *min_element( + first_index_or_repeated.begin(), first_index_or_repeated.end() + ); + + return first_index < index ? first_index : -1; + } + + private: + static constexpr int kNotUsed = INT_MAX; + static constexpr int kRepeated = INT_MAX - 1; + vector first_index_or_repeated; + int index; +}; diff --git a/01-15/4.First-Unique-Character-in-a-String/Ex2.cpp b/01-15/4.First-Unique-Character-in-a-String/Ex2.cpp new file mode 100644 index 0000000..600608c --- /dev/null +++ b/01-15/4.First-Unique-Character-in-a-String/Ex2.cpp @@ -0,0 +1,75 @@ +#if __has_include("../../debug.hpp") +#include "../../debug.hpp" +#endif +// ここまでローカルでのデバッグ用なので気にしないでください -------------------- + +#include +#include +#include + +using namespace std; + +// こちらは番外編です。入力がintのstreamだったときです。 +// <時間> +// 15分 +// <疑問・不安点(・個人的な感想、違う意見があれば教えてほしいもの)> +// - 若干分かりにくかったが、もう一度書き直したらわかりやすくなった +class SolutionStream { + public: + int firstUniqueNum(int num) { + if (duplicated_numbers.contains(num)) { + if (numbers.empty()) throw new range_error("No unique number was found"); + return numbers.front(); + } + + if (auto it = unique_numbers.find(num); it != unique_numbers.end()) { + unique_numbers.erase(it); + duplicated_numbers.insert(num); + } else { + unique_numbers.insert(num); + numbers.push(num); + } + + while (!numbers.empty() && duplicated_numbers.contains(numbers.front())) { + numbers.pop(); + } + + if (numbers.empty()) throw new range_error("No unique number was found"); + return numbers.front(); + } + + private: + queue numbers; + set unique_numbers; + set duplicated_numbers; +}; + +// <時間> +// 不明 +// <疑問・不安点(・個人的な感想、違う意見があれば教えてほしいもの)> +class SolutionStream2 { + public: + int firstUniqueNum(int num) { + if (duplicated_numbers.contains(num)) { + if (numbers.empty()) throw new range_error("No unique number was found"); + return numbers.front(); + } + if (auto it = unique_numbers.find(num); it != unique_numbers.end()) { + unique_numbers.erase(it); + duplicated_numbers.insert(num); + while (!numbers.empty() && duplicated_numbers.contains(numbers.front())) { + numbers.pop(); + } + if (numbers.empty()) throw new range_error("No unique number was found"); + } else { + unique_numbers.insert(num); + numbers.push(num); + } + return numbers.front(); + } + + private: + queue numbers; + set unique_numbers; + set duplicated_numbers; +}; diff --git a/01-15/4.First-Unique-Character-in-a-String/README.md b/01-15/4.First-Unique-Character-in-a-String/README.md new file mode 100644 index 0000000..73052f9 --- /dev/null +++ b/01-15/4.First-Unique-Character-in-a-String/README.md @@ -0,0 +1,3 @@ +# 387. First Unique Character in a String + +