diff --git a/300/300.md b/300/300.md new file mode 100644 index 0000000..b4f0d9b --- /dev/null +++ b/300/300.md @@ -0,0 +1,104 @@ +## 何も見ずに解いてみる + +後半30問はC++で解いてみようと思います。 +まだC++はあまりわかっていないのでいろいろとLLMに聞きながら書きました。 + +```cpp +#include +#include + +class Solution { +public: + int lengthOfLIS(vector& nums) { + std::unordered_map last_num_to_max_length; + int min_value = std::numeric_limits::min(); + last_num_to_max_length[min_value] = 0; + for (auto num : nums) { + int max_num = 0; + for (auto [last_num, max_length] : last_num_to_max_length) { + if (last_num < num) { + max_num = std::max(max_num, max_length + 1); + } + } + last_num_to_max_length[num] = max_num; + } + auto max_it = std::max_element(last_num_to_max_length.begin(), last_num_to_max_length.end(), + [](const auto& a, const auto& b) { + return a.second < b.second; + } + ); + return max_it->second; + } +}; +``` + +### Follow up: Can you come up with an algorithm that runs in O(n log(n)) time complexity? +(末尾の数字, それで実現できる最長の長さ) のtupleみたいなものをlistとしてどちらの要素に関してもincreasingになるように保存して、二分探索でindexを見つけて更新していくことでできるのではないかと思ったが、 +更新の際に (今見ている数字, それより小さい数字の最長の長さ + 1) をinsertして、次に大きい数字と同じ文字列長だったらそっちを消す、 みたいなことをやる必要があり、それに一回あたりO(n)かかって結局O(n^2)かかってしまいそう + +## 色々調べてみる + +https://github.com/irohafternoon/LeetCode/pull/34/files +https://github.com/Miyamoto-tryk/leetcode-arai60/pull/4/files +https://github.com/Ryotaro25/leetcode_first60/pull/34/files +https://github.com/tokuhirat/LeetCode/pull/31/files +https://github.com/Satorien/LeetCode/pull/31/files + +https://cpprefjp.github.io/reference/vector/vector.html +https://cpprefjp.github.io/reference/utility/pair.html +https://cpprefjp.github.io/reference/algorithm/lower_bound.html + +O(n^2)のDPの解法ではhashmapではなくvectorを使っている人が多かった。個人的には辞書の方が直感的な気もする。 + +実現しうる文字列長以下のすべての数字について末尾にできる最小の数字が存在するので、文字列長をindexとする配列で二分探索を行って、随時indexを更新していけばよい。 +あるいは自分が考えていたようにtupleのlistを作っても、次に大きい数字のtupleを直接更新すればできそう。 + +```cpp +class Solution { +public: + int lengthOfLIS(vector& nums) { + vector> tail_len_pairs; + for (const auto& num : nums) { + auto it = std::lower_bound(tail_len_pairs.begin(), tail_len_pairs.end(), num, + [](const std::pair& p, const int val) { + return p.first < val; + }); + if (it == tail_len_pairs.end()) { + tail_len_pairs.push_back({num, tail_len_pairs.size() + 1}); + } else { + it->first = num; + } + } + return tail_len_pairs.back().second; + } +}; +``` + +普通にやったほうがわかりやすそうか。 + +## 最終コード + +変数名の決め方が難しい。。 + +```cpp +#include +#include +using namespace std; + +class Solution { +public: + int lengthOfLIS(vector& nums) { + vector minimum_tails; + for (const auto& num : nums) { + auto it = lower_bound(minimum_tails.begin(), minimum_tails.end(), num); + if (it == minimum_tails.end()) { + minimum_tails.push_back(num); + } else { + *it = num; + } + } + return minimum_tails.size(); + } +}; +``` +