diff --git a/46/46.md b/46/46.md new file mode 100644 index 0000000..d888205 --- /dev/null +++ b/46/46.md @@ -0,0 +1,94 @@ +## 何も見ずに解いてみる + +```cpp +class Solution { +public: + vector> permute(vector& nums) { + vector> result; + if (nums.size() == 0) { + result.push_back({}); + } + for (int i = 0; i < nums.size(); ++i) { + vector nums_copy = nums; + nums_copy.erase(nums_copy.begin() + i); + for (auto& vec : permute(nums_copy)) { + vec.insert(vec.begin(), nums[i]); + result.push_back(vec); + } + } + return result; + } +}; +``` + +## 他の人のコードを見てみる + +https://github.com/tokuhirat/LeetCode/pull/50/files +https://github.com/ryosuketc/leetcode_arai60/pull/39/files +https://github.com/Ryotaro25/leetcode_first60/pull/54/files + +swapを使って書いたコードは、下のコードを + +- sub_permutationをnumsのdecided_untilより前として管理する +- unused_numsをnumsのdecided_until以降として管理する + +ことでより早くしたカッコイイバージョンだと捉えられる気がしますね。 +Geminiによるとメモリ上で違う位置にあるsub_permutationとunused_numsをいちいち反復横跳びしなくてよくなっているという点でも高速化に貢献しているらしいです。(真偽のほどは検証していません・・・) + +```cpp +class Solution { +public: + vector> permute(vector& nums) { + vector> result; + vector initial_vector = {}; + unordered_set nums_set(nums.begin(), nums.end()); + permuteHelper(result, initial_vector, nums_set); + return result; + } +private: + void permuteHelper(vector>& result, vector& sub_permutation, unordered_set& unused_nums) { + if (unused_nums.empty()) { + result.emplace_back(sub_permutation); + return; + } + // unused_numsでそのまま回すとfor文の最中にいじってるのが原因でエラー吐くのでコピーして回します + unordered_set unused_nums_copy(unused_nums.begin(), unused_nums.end()); + for (int num : unused_nums_copy) { + unused_nums.erase(num); + sub_permutation.emplace_back(num); + permuteHelper(result, sub_permutation, unused_nums); + sub_permutation.pop_back(); + unused_nums.insert(num); + } + } +}; +``` + +resultにpush_backとかemplace_backするとき順列をコピーしてから入れなくて大丈夫なのかと思ったんですが、オブジェクトそのものではなくてコンストラクタの引数として渡されてそれをもとに新しい要素が作られるという挙動なのでいらないみたいです。pythonのlist.appendとは違いますね。 + +## 最終コード + +```cpp +class Solution { +public: + vector> permute(vector& nums) { + vector> result; + permuteHelper(result, nums, 0); + return result; + } + void permuteHelper(vector>& result, vector& nums, int decided_until) { + if (decided_until == nums.size()) { + result.emplace_back(nums); + return; + } + for (int i = decided_until; i < nums.size(); ++i) { + swap(nums[decided_until], nums[i]); + permuteHelper(result, nums, decided_until + 1); + swap(nums[decided_until], nums[i]); + } + } +}; +``` + +そういえばこれnums参照渡しで渡されてるので(最終的に戻ってくるときは元の状態で戻ってきますが)関数が走ってるとき中身の要素がめっちゃswapされることになると思うんですが、大丈夫なんでしょうか。 +numsが変化したときにそれを何らかの方法で検出して何か操作を行う、みたいな仕組みが組まれてると怪しいかもしれません。コピーしたほうが安心ですかね?