From e6b861ab57de8820205b5c34fd69d0822ac67ecb Mon Sep 17 00:00:00 2001 From: potrue <126231160+potrue@users.noreply.github.com> Date: Tue, 19 Aug 2025 04:00:35 +0900 Subject: [PATCH 1/2] 46. Permutations https://leetcode.com/problems/permutations/description/ --- 46/46.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 46/46.md diff --git a/46/46.md b/46/46.md new file mode 100644 index 0000000..9e7aca8 --- /dev/null +++ b/46/46.md @@ -0,0 +1,93 @@ +## 何も見ずに解いてみる + +```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が変化したときにそれを何らかの方法で検出して何か操作を行う、みたいな仕組みが組まれてると怪しいかもしれません。コピーしたほうが安心ですかね? From 4df15ae892b2aabcdf6e1c24144bba62db87ecb0 Mon Sep 17 00:00:00 2001 From: potrue <126231160+potrue@users.noreply.github.com> Date: Tue, 19 Aug 2025 04:04:25 +0900 Subject: [PATCH 2/2] Update 46.md --- 46/46.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/46/46.md b/46/46.md index 9e7aca8..d888205 100644 --- a/46/46.md +++ b/46/46.md @@ -28,9 +28,11 @@ 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以降として管理する -ことでより早くしたカッコイイバージョンだと捉えられる気がしますね。 + +- sub_permutationをnumsのdecided_untilより前として管理する +- unused_numsをnumsのdecided_until以降として管理する + +ことでより早くしたカッコイイバージョンだと捉えられる気がしますね。 Geminiによるとメモリ上で違う位置にあるsub_permutationとunused_numsをいちいち反復横跳びしなくてよくなっているという点でも高速化に貢献しているらしいです。(真偽のほどは検証していません・・・) ```cpp @@ -62,8 +64,7 @@ private: }; ``` -resultにpush_backとかemplace_backするとき順列をコピーしてから入れなくて大丈夫なのかと思ったんですがオブジェクトそのものではなくてコンストラクタの引数として渡されてそれをもとに新しい要素が作られるという挙動なのでいらないみたいです。 -pythonのlist.appendとは違いますね。 +resultにpush_backとかemplace_backするとき順列をコピーしてから入れなくて大丈夫なのかと思ったんですが、オブジェクトそのものではなくてコンストラクタの引数として渡されてそれをもとに新しい要素が作られるという挙動なのでいらないみたいです。pythonのlist.appendとは違いますね。 ## 最終コード @@ -89,5 +90,5 @@ public: }; ``` -そういえばこれnums参照渡しで渡されてるので(最終的に戻ってくるときは元の状態で戻ってきますが)関数が走ってるとき中身の要素がめっちゃswapされることになると思うんですが、大丈夫なんでしょうか。 +そういえばこれnums参照渡しで渡されてるので(最終的に戻ってくるときは元の状態で戻ってきますが)関数が走ってるとき中身の要素がめっちゃswapされることになると思うんですが、大丈夫なんでしょうか。 numsが変化したときにそれを何らかの方法で検出して何か操作を行う、みたいな仕組みが組まれてると怪しいかもしれません。コピーしたほうが安心ですかね?