-
Notifications
You must be signed in to change notification settings - Fork 0
31. Next Permutation #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| class Solution { | ||
| public: | ||
| void nextPermutation(vector<int>& nums) { | ||
| int left = FindDecreasingIndex(nums); | ||
| // nums全体が降順になっている場合 | ||
| if (left == -1) { | ||
| reverse(nums.begin(), nums.end()); | ||
| return; | ||
| } | ||
| int right = FindRightmostLarger(nums, left); | ||
| swap(nums[left], nums[right]); | ||
| reverse(nums.begin() + left + 1, nums.end()); | ||
| } | ||
|
|
||
| private: | ||
| // 右側が降順になっている範囲の直前のインデックスを探す | ||
| int FindDecreasingIndex(const vector<int>& nums) { | ||
| int index = nums.size() - 2; | ||
| while (index >= 0 && nums[index] >= nums[index + 1]) { | ||
| index--; | ||
| } | ||
| return index; | ||
| } | ||
|
|
||
| // 大きい値のうち、最も右側のものを見つける | ||
| int FindRightmostLarger(vector<int>& nums, int left) { | ||
| auto it = lower_bound(nums.begin() + left + 1, nums.end(), nums[left], greater<int>()); | ||
| return distance(nums.begin(), it) - 1; | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ## ステップ1 | ||
| >if all the permutations of the array are sorted in one container according to their lexicographical order, then the next permutation of that array is the permutation that follows it in the sorted container. | ||
| [1,2,3]の次は[1,3,2]ということ | ||
| >If such arrangement is not possible, the array must be rearranged as the lowest possible order | ||
| [3,2,1]の次は[1,2,3]に戻るということ | ||
|
|
||
| これだけだと分からないので | ||
| [1,2,3,4]で考える | ||
| [1,2,4,3] | ||
| [1,3,2,4] | ||
| [1,3,4,2] | ||
| [1,4,2,3] | ||
| [1,4,3,2] | ||
| [2,1,3,4] | ||
| . | ||
| . | ||
| . | ||
| 20分ほど考えて分からなかったので、回答を見る | ||
| 前に、next_permutationを使った際に実装方法まで見ておけばよかった | ||
| https://en.cppreference.com/w/cpp/algorithm/next_permutation | ||
|
|
||
| 次の順列を作る流れは以下の通りとなっている。 | ||
| 1.後ろから探索して、numsの中で最初に、前から昇順に並んでいるインデックスを探す | ||
| 2.1のインデックスに対応する値より大きい、最も右にある要素を探す | ||
| 3.1と2の要素を入れ替える | ||
| 4.1.のインデックス以降を昇順にする(元々は降順) | ||
|
|
||
|
|
||
| ## ステップ2 | ||
| ・first_increasing_order_index | ||
| この変数名から何をしたいのか分かりにくいのと、 | ||
| 実際はfirst_increasing_order_index - 1として使っていることが多いため | ||
| 単にpivotとかでも良さそう | ||
|
|
||
| ・next_larger_index | ||
| nextよりrightmostの方がまだ良さそう | ||
| コメントがないと何をしているのか伝わらない | ||
| コメントも微妙なので、改善等あれば言って頂けると助かります。 | ||
|
|
||
| ・reverse | ||
| pivot以降を逆順に並び変える箇所について | ||
| 元々pivot以降は降順に並んでいるので、reverseを使い結果として昇順に並び替えているが | ||
| sortを使った方がわかりやすいような気がする | ||
| O(n)からO(n log n)になるが、昇順に並び替えているというのは伝わりそう | ||
|
|
||
| next_permutation関数を使うのは、求めらていないだろう | ||
|
|
||
| ## ステップ3 | ||
| **3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. なんとなく解くことが目的化しているというか、きれいなコードを GitHub に上げることが目的になっている感触を微かに持っています。(オンラインなのではっきりとは分かりません。) ただ、好きなようにやればいいとは思います。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @oda |
||
|
|
||
| ## 他の方の解法 | ||
|
|
||
| 自分の知らない関数をいくつか使われていて勉強になる | ||
| https://en.cppreference.com/w/cpp/algorithm/adjacent_find | ||
| https://en.cppreference.com/w/cpp/algorithm/iter_swap | ||
|
|
||
| >// Find the first DSC pair from the tail : [4,(5,7),6,3,2,1] | ||
| >// to point to the second element of the pair : | ||
| >// [4,(*5,7),6,3,2,1] | ||
| この辺りのコメントの書き方が分かりやすいと思った。 | ||
|
|
||
| iteratorを使って処理することでコードを綺麗に纏められそう | ||
| https://github.com/usatie/leetcode/pull/2/commits/f0875e0db129eb5eabcb5fd6363de8258befe3ce | ||
|
|
||
|
|
||
| >引数は広い型で指定した方が使える場面が増えるかなと思って、一応そうしてみてます。 | ||
| 目先の問題に囚われないで実務を想定している。この考え方なるほどです。 | ||
|
|
||
| 二分探索の選択肢は持っておく | ||
| lower_bound.cppに実装 | ||
| https://github.com/fhiyo/leetcode/pull/56/commits/6836d3c8ee01216ccd303dc5df93b199311a4e18 | ||
|
|
||
| >実際はleftより後ろの要素のうち、nums[left]より大きい一番後ろの要素のindexを返しているので | ||
| 確かに処理に対して適切な名前を付けるは難しい | ||
| 関数に分けて、関数名や引数から処理を予想させるは良さそう | ||
| https://github.com/Mike0121/LeetCode/pull/15/commits/cac8eb6c5ecc3db4644cb5f9b34c7046238b53e1 | ||
|
|
||
| ## Discordなど | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| class Solution { | ||
| public: | ||
| void nextPermutation(vector<int>& nums) { | ||
| int first_increasing_order_index = nums.size() - 1; | ||
| while (first_increasing_order_index > 0) { | ||
| if (nums[first_increasing_order_index - 1] < nums[first_increasing_order_index]) { | ||
| break; | ||
| } | ||
| first_increasing_order_index--; | ||
| } | ||
|
Comment on lines
+4
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これを見て、first_increasing_order_index の初期化がここで終了したという理解は構造からは得られないと思うんですよね。たとえば、下はどうでしょうか。 int first_increasing_order_index = 0;
for (int i = num.size() - 1; i > 0; --i) {
if (...) {
first_increasing_order_index = i;
break;
}
}これは、0 がデフォルトで後ろから条件を満たすものを探して初期化したと読めますね。 const int first_increasing_order_index = get_first_increasing_order(nums);これも初期化したと読めますね。 初期化するために繰り返し変更すると意図が追いにくくなるでしょう。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ありがとうございます。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @oda なるほどです。メタ認知力を鍛えたいと思ってそう言ったタイトルの本を読んでみたのですが、おすすめの本などあったりしますでしょうか? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. よく分かりません。 |
||
|
|
||
| if (first_increasing_order_index > 0) { | ||
| int next_larger_index = nums.size() - 1; | ||
| while (nums[next_larger_index] <= nums[first_increasing_order_index - 1]) { | ||
| next_larger_index--; | ||
| } | ||
| swap(nums[first_increasing_order_index - 1], nums[next_larger_index]); | ||
| } | ||
|
|
||
| reverse(nums.begin() + first_increasing_order_index, nums.end()); | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| class Solution { | ||
| public: | ||
| void nextPermutation(vector<int>& nums) { | ||
| int pivot_index = nums.size() - 1; | ||
|
|
||
| // numsを後ろから探索して昇順となっている箇所をpivotとする | ||
| while (pivot_index > 0 && nums[pivot_index - 1] >= nums[pivot_index]) { | ||
| pivot_index--; | ||
| } | ||
|
|
||
| // 先頭から見てnums全てが降順に並んでいる場合は対象外 | ||
| // pivot_index - 1より大きく、最も右側の位置に存在している値を探して | ||
| // pivot_index - 1と入れ替える | ||
| if (pivot_index > 0) { | ||
| int rightmost_larger_index = nums.size() - 1; | ||
| while (nums[rightmost_larger_index] <= nums[pivot_index - 1]) { | ||
| rightmost_larger_index--; | ||
| } | ||
| swap(nums[pivot_index - 1], nums[rightmost_larger_index]); | ||
| } | ||
|
|
||
| sort(nums.begin() + pivot_index, nums.end()); | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| class Solution { | ||
| public: | ||
| void nextPermutation(vector<int>& nums) { | ||
| int pivot_index = nums.size() - 1; | ||
| while (pivot_index > 0 && nums[pivot_index - 1] >= nums[pivot_index]) { | ||
| pivot_index--; | ||
| } | ||
|
|
||
| if (pivot_index > 0) { | ||
| int rightmost_larger_index = nums.size() - 1; | ||
| while (nums[rightmost_larger_index] <= nums[pivot_index - 1]) { | ||
| rightmost_larger_index--; | ||
| } | ||
| swap(nums[pivot_index - 1], nums[rightmost_larger_index]); | ||
| } | ||
|
|
||
| sort(nums.begin() + pivot_index, nums.end()); | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| class Solution { | ||
| public: | ||
| void nextPermutation(vector<int>& nums) { | ||
| // 後ろから探索して、numsの中で最初に前から昇順に並んでいるインデックスを探す | ||
| int first_increasing_order_index = 0; | ||
| for (int i = nums.size() - 1; i > 0; i--) { | ||
| if (nums[i - 1] < nums[i]) { | ||
| first_increasing_order_index = i; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (first_increasing_order_index > 0) { | ||
| // first_increasing_order_index より大きい値を持つ最も右の要素を探す | ||
| for (int i = nums.size() - 1; i >= first_increasing_order_index; i--) { | ||
| if (nums[i] > nums[first_increasing_order_index - 1]) { | ||
| swap(nums[first_increasing_order_index - 1], nums[i]); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| reverse(nums.begin() + first_increasing_order_index, nums.end()); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nextPermutationとこちらの関数名のネーミングルールが揃っていないことに違和感があります。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@usatie
レビューありがとうございます。
この会では可能な限りGoogleのスタイルガイドに合わせてコードを書いております。これはこの会以外ではC++を使うことがないためです。
全体で統一できればなのですが、LeetCodeで用意されている部分は仕方ないかなと思っております。
https://google.github.io/styleguide/cppguide.html#Function_Names