31. Next Permutation#2
Conversation
|
|
||
| #define T(...) \ | ||
| ({ \ | ||
| std::cout << #__VA_ARGS__ " -> "; \ |
There was a problem hiding this comment.
可変引数マクロですね。確かに、そのまま文字列化するならば、こうするしかないですが、逆に変数を引数に与えると
{i, j, k} -> [1,2,3]
と表示されるはずで、これは意図通りなのか、あくまでも、並んでいる数字がみたいのかは考えどころでしょう。
std::initializer_list でもいいですし、可変引数テンプレートでもよいでしょう。
({;;}) は、GCC 拡張だったかと思います。
また、返り値が最後の式の評価になるので、最後の行で cout << endl; すると嵌ります。
https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
単に {;;} とするのも手ですが、{;;}; と展開されるので、
if () T(); else {}で事故りそうです。
ラムダの呼び出しに変えるのは一つです。[&]{std::cout << "";}()
古典的な do{}while(0) を使う手もあります。
テスト目的なのでよいという考えもありますが、結構嵌りそうなコードと感じました。
There was a problem hiding this comment.
今回は以前使ったことがあったStringizing operator (#)をあまり考えることなく使ってしまいましたが、std::initializer_listという手もあるのですね。
https://learn.microsoft.com/en-us/cpp/preprocessor/stringizing-operator-hash?view=msvc-170
https://en.cppreference.com/w/cpp/preprocessor/replace#.23_and_.23.23_operators
https://en.cppreference.com/w/cpp/utility/initializer_list
返り値が最後の式の評価になってしまうとは知りませんでした。単純にT()が{;;};と展開されてしまうのがいやだなーと思っていたのですが、それ以外にも問題があるのですね。複数行マクロの引き出しが増えて、とても勉強になりました。
{;;}- ラムダ呼び出し
do {} while (0)
| 4. adjacent_findとupper_boundが今回の例にはピッタリ | ||
| 5. reverse(begin, pivot)としておけば最初に降順ペアが見つからなかった場合にも | ||
| 正しく動作するのでearly returnしなくても一箇所にまとめられる。 | ||
| */ |
There was a problem hiding this comment.
https://en.cppreference.com/w/cpp/algorithm/next_permutation
一応こちらに参考実装がございます。
There was a problem hiding this comment.
なるほどこんなものが標準ライブラリで提供されていたんですね。
以下のように使えるとchatgptに教えてもらってなるほど、確かにこれがあると使いやすいなと理解できました。
std::vector<int> v = {1, 2, 3};
// まずは v を昇順にソートしておく(これが「最初の順列」)
std::sort(v.begin(), v.end());
// 辞書順ですべての順列を列挙
do {
// v を使った処理
// (ここで順列 v を出力したり、何かしらのチェックを行う)
} while (std::next_permutation(v.begin(), v.end()));
There was a problem hiding this comment.
以下の二つについても使ったことがなかったので、参考実装を見て勉強になりました。
std::make_reverse_iterator
http://en.cppreference.com/w/cpp/iterator/make_reverse_iterator
std::is_sorted_until
http://en.cppreference.com/w/cpp/algorithm/is_sorted_until
| @@ -0,0 +1,31 @@ | |||
| #include "step3.cpp" | |||
There was a problem hiding this comment.
.cpp を include していると、違和感を感じます。実務では、ヘッダーファイルを作成し、それを include し、リンカーでリンクすると思います。仮に .cpp ファイルを include するとしても、かなり特殊なケースだと思いますので、なぜ .cpp を直接 include するか、コメントで説明を付け加えると思います。
There was a problem hiding this comment.
ありがとうございます。確かにそうですね。ちょっと面倒だと思ってしまったのですが各ステップのファイルをheaderファイルにして、次回からincludeもそこでやろうと思います。
しかも今気づいたのですが、コミット前にclang-formatでフォーマットをかけてしまった際にinclude順が変わってしまっていて、このままだとコンパイルが通りませんでした。
|
|
||
| int tail = nums.size() - 1; | ||
| int i, j; | ||
| // 1. Find the first ASC pair nums[i] and nums[i+1] |
There was a problem hiding this comment.
略語は読むにあたり、やや認知負荷が高く感じます。単語はできる限りフルスペルで書いたほうが良いと思います。
| NAME = a.out | ||
| SRC = main.cpp | ||
| CXX = g++ | ||
| CXXFLAGS = -Wall -Wextra -Werror -std=c++11 |
There was a problem hiding this comment.
ローカルの実行環境はLeetCodeに合わせるのはどうでしょうか?
clang 19 using the latest C++ 23 standard, and libstdc++ provided by GCC 14.
There was a problem hiding this comment.
ありがとうございます。なるほどそういう手がありましたか・・・!やってみます!
There was a problem hiding this comment.
自分はローカルの環境構築をdevenv.shで行っているのですが、1時間ほどこの設定にするために時間を溶かしてしまってそれでもまだできなさそうなので、一旦諦めます><
…ession to lambda)
問題 : https://leetcode.com/problems/next-permutation/
言語 : C++
step3をやる際に、念の為ローカルでテストができるようにmain.cppとMakefileも用意しています。