diff --git a/8/8.md b/8/8.md new file mode 100644 index 0000000..ecd49fe --- /dev/null +++ b/8/8.md @@ -0,0 +1,212 @@ +## 何も見ずに解いてみる + +初号機 + +```cpp +class Solution { +public: + int myAtoi(string s) { + const unordered_map DIGIT_MAPPING = { + {'0', 0}, + {'1', 1}, + {'2', 2}, + {'3', 3}, + {'4', 4}, + {'5', 5}, + {'6', 6}, + {'7', 7}, + {'8', 8}, + {'9', 9}, + }; + int sign = 1; + auto it = s.begin(); + while (it != s.end() && *it == ' ') { + ++it; + } + if (it != s.end() && (*it == '+' || *it == '-')) { + if (*it == '+') { + sign = 1; + } + if (*it == '-') { + sign = -1; + } + ++it; + } + while (it != s.end() && *it == '0') { + ++it; + } + auto rend = reverse_iterator(it); + while (it != s.end() && DIGIT_MAPPING.contains(*it)) { + ++it; + } + auto rit = reverse_iterator(it); + long long num = 0; + long long power = 1; + while (rit != rend) { + if (power > numeric_limits::max()) { + if (sign == 1) { + return numeric_limits::max(); + } else { + return numeric_limits::min(); + } + } + num += DIGIT_MAPPING.at(*rit) * power; + power *= 10; + ++rit; + } + if (num * sign > numeric_limits::max()) { + return numeric_limits::max(); + } + if (num * sign < numeric_limits::min()) { + return numeric_limits::min(); + } + return num * sign; + } +}; +``` + +二号機(あんまり見やすくならなかった。。。) + +```cpp +class Solution { +public: + int myAtoi(string s) { + string_view whitespace_removed = removeLeadingWhitespace(s); + auto [sign, sign_removed] = checkAndRemoveSign(whitespace_removed); + string_view zeroes_removed = removeLeadingZeroes(sign_removed); + string_view valid_digits = extractValidDigits(zeroes_removed); + if (valid_digits.size() > 10) { + if (sign == 1) { + return numeric_limits::max(); + } else { + return numeric_limits::min(); + } + } + long long num = 0; + long long power = 1; + for (auto rit = valid_digits.rbegin(); rit != valid_digits.rend(); ++rit) { + num += DIGIT_MAPPING.at(*rit) * power; + power *= 10; + } + return clamp(num * sign, numeric_limits::min(), numeric_limits::max()); + } +private: + const unordered_map DIGIT_MAPPING = { + {'0', 0}, + {'1', 1}, + {'2', 2}, + {'3', 3}, + {'4', 4}, + {'5', 5}, + {'6', 6}, + {'7', 7}, + {'8', 8}, + {'9', 9}, + }; + string_view removeLeadingWhitespace(string_view s) { + auto it = s.begin(); + while (it != s.end() && *it == ' ') { + ++it; + } + return string_view(it, s.end()); + } + tuple checkAndRemoveSign(string_view s) { + if (s.empty()) { + return {1, s}; + } + if (s.front() == '+') { + return {1, string_view(s.begin() + 1, s.end())}; + } + if (s.front() == '-') { + return {-1, string_view(s.begin() + 1, s.end())}; + } + return {1, s}; + } + string_view removeLeadingZeroes(string_view s) { + auto it = s.begin(); + while (it != s.end() && *it == '0') { + ++it; + } + return string_view(it, s.end()); + } + string_view extractValidDigits(string_view s) { + auto it = s.begin(); + while (it != s.end() && DIGIT_MAPPING.contains(*it)) { + ++it; + } + return string_view(s.begin(), it); + } +}; +``` + +## 他の人のコードを見てみる + +https://github.com/tokuhirat/LeetCode/pull/59/files +https://github.com/ryosuketc/leetcode_arai60/pull/59/files +https://github.com/Ryotaro25/leetcode_first60/pull/64/files +https://github.com/philip82148/leetcode-swejp/pull/6/files + +有効桁のところは別に後ろから見なくても、結果それ自体を桁が増えるごとに10倍していけば数値にできるのか。 + +'0'から'9'までの数字がcharをintに変換したときにこの順に連続で並んでることは保証されているっぽい? +https://stackoverflow.com/questions/9416926/are-the-character-digits-0-9-required-to-have-contiguous-numeric-values +https://en.cppreference.com/w/c/language/charset.html + +https://cpprefjp.github.io/reference/string/basic_string.html +"find_first_not_of"とかは使えそうかも。 + +https://en.cppreference.com/w/cpp/string/byte/atoi.html +サンプル実装が書いてある(オーバーフローのチェックはしてないっぽい) +C言語の文字列はchar[]として保存されてて最後に末端文字なるものがついているらしく、イテレーターが終端にたどり着いたかどうかを気にしなくていいらしい。 +(*strが終端文字になった時点で全部スルーされる) +[c_str](https://cpprefjp.github.io/reference/string/basic_string/c_str.html)というので変換すればこの問題でも終端チェックしなくてもよくなるかも。 + +iswhitespaceの略かなと思ってiswspaceのページも開いたらワイド文字とかいう変な概念出てきた +https://en.cppreference.com/w/cpp/string/wide/iswspace.html +https://ja.wikipedia.org/wiki/%E3%83%AF%E3%82%A4%E3%83%89%E6%96%87%E5%AD%97 + +https://github.com/philip82148/leetcode-swejp/pull/6/files#r1853735872 +オーバーフローするかどうかを判定してくれる組み込み関数もあるらしい + +std::isdigitについて、 +[日本語版のドキュメント](https://cpprefjp.github.io/reference/cctype/isdigit.html)には +「ch が数字かどうかを判定する(判定はロケールの影響を受ける)。」 +ってあるけど、 +[英語版のドキュメント](https://en.cppreference.com/w/cpp/string/byte/isdigit.html)には +"isdigit and isxdigit are the only standard narrow character classification functions that are not affected by the currently installed C locale." +ってある。 +この二つって別に両立するんでしょうか?それとも日本語版のドキュメントが間違ってるんですかね(分かる方教えてください。。。) + +## 最終コード + +```cpp +class Solution { +public: + int myAtoi(string s) { + auto it = s.begin(); + while (it != s.end() && isspace(*it)) { + ++it; + } + int sign = 1; + if (it != s.end() && (*it == '+' || *it == '-')) { + if (*it == '-') { + sign = -1; + } + ++it; + } + long long num = 0; + while (it != s.end() && isdigit(*it)) { + int digit = *it - '0'; + num = num * 10 + digit * sign; + if (num > INT_MAX) { + return INT_MAX; + } + if (num < INT_MIN) { + return INT_MIN; + } + ++it; + } + return num; + } +}; +```