-
Notifications
You must be signed in to change notification settings - Fork 0
392. Is Subsequence #5
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: review-base
Are you sure you want to change the base?
Changes from all commits
6138b56
32ef7f1
7d79512
f56e91e
b430054
c59dc63
2482631
44c5d15
db0790a
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,12 @@ | ||
| NAME = a.out | ||
| SRC = main.cpp | ||
| CXX = g++ | ||
| CXXFLAGS = -Wall -Wextra -Werror -std=c++23 | ||
|
|
||
| all: $(NAME) | ||
|
|
||
| $(NAME): $(SRC) step1.hpp step2.hpp step3.hpp | ||
|
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. また、普通はヘッダーファイルはコンパイラに渡さずソースファイル(.cpp)から#includeのみします
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. あ、すみません、誤読してましたmm |
||
| $(CXX) -o $(NAME) $(SRC) $(CXXFLAGS) | ||
|
|
||
| run: $(NAME) | ||
| ./$(NAME) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #include <iostream> | ||
| #include <string> | ||
|
|
||
| #include "step2.hpp" | ||
|
|
||
| #define test(subsequence, text, expected) \ | ||
| [] { \ | ||
| bool actual = Solution4().isSubsequence(subsequence, text); \ | ||
| std::cout << "Test: " << #subsequence << " in " << #text << "\" : "; \ | ||
| if (actual == expected) { \ | ||
| std::cout << "OK" << std::endl; \ | ||
| } else { \ | ||
| std::cout << "Failed" << std::endl \ | ||
| << "Expected: " << expected << ", but got: " << actual \ | ||
| << std::endl; \ | ||
| } \ | ||
| }() | ||
|
|
||
| int main(void) { | ||
| test("abc", "ahbgdc", true); | ||
| test("axc", "ahbgdc", false); | ||
| test("", "ahbgdc", true); | ||
| test("a", "", false); | ||
| test("a", "b", false); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #ifndef STEP1_HPP | ||
| #define STEP1_HPP | ||
|
|
||
| /* | ||
| 何がわからなかったか | ||
| - N/A | ||
| 何を考えて解いていたか | ||
| - tを前から舐めていけばいい | ||
| 正解してから気づいたこと | ||
| - Follow upに対応するためには、tを毎回舐めると無駄なので、前処理をしておいて | ||
| ある文字がtのなかのどこにあるかを高速に調べられるようにしておくといい | ||
| */ | ||
| #include <string> | ||
|
|
||
| class Solution { | ||
| public: | ||
| // Naive solution | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| if (subsequence.empty()) { | ||
| return true; | ||
| } | ||
| size_t i = 0; | ||
| for (auto c : text) { | ||
| if (subsequence[i] == c) { | ||
| ++i; | ||
| if (subsequence.size() == i) { | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
| }; | ||
|
|
||
| #endif // STEP1_HPP |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,246 @@ | ||
| /* | ||
| 講師陣はどのようなコメントを残すだろうか? | ||
| - | ||
| 他の人のコードを読んで考えたこと | ||
| - https://github.com/philip82148/leetcode-arai60/pull/7 | ||
| 関数プロトタイプとかは与えられたものと考えるのではなく、より好ましいものに | ||
| 変えちゃった方がいい | ||
| - https://github.com/Yoshiki-Iwasa/Arai60/pull/62 | ||
| Edit distanceの問題として捉えることもできるのか. | ||
| https://en.wikipedia.org/wiki/Levenshtein_distance | ||
| DPでも解ける, なるほどやってみよう | ||
| 改善する時にかんがえたこと | ||
| - 同じtextに対してqueryが来ないなら初期化したcharacterPositionsをメンバ変数で | ||
| 持ってもいいし、Constructorで初期化してもいい。 | ||
| - Constructorで初期化する場合関数プロトタイプが変わってテストをそのためだけに | ||
| 書き直したり用意するのが面倒なのでここではやってない。 | ||
| - 複数のtextに対してsubsequenceをチェックする場合、textごとに初期化する。 | ||
| ただし、textが大きい場合はmapのkeyとしてtextも保存する羽目になるので、 | ||
| メモリを食ってしまうかもしれない。衝突を許容して少ない数のtextだったら | ||
| key自体もhashにしてしまってもいいかもしれない? | ||
| - `auto positions = characterPositions[c];`と元々はしていたけれど | ||
| referenceにしておかないと意図せぬcopyが発生してしまう | ||
| */ | ||
| #ifndef STEP2_HPP | ||
| #define STEP2_HPP | ||
|
|
||
| #include <functional> | ||
| #include <map> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| class Solution1 { | ||
| // Follow up | ||
| /* Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= 109, | ||
| * and you want to check one by one to see if t has its subsequence. In this | ||
| * scenario, how would you change your code? | ||
| */ | ||
| public: | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| std::map<char, std::vector<size_t>> characterPositions; | ||
|
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. vectorの代わりにsetでもいいんじゃないでしょうか(L49のlower_boundの書き方がすっきりします)
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. なるほど、要素がuniqueであることが保証されているためsetでも良いのですね。 https://en.cppreference.com/w/cpp/container/set setを使う場合は 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. 現実的には log N の部分は、定数と同程度にしか気にしないと思います。N が 1T としても40とかですからね。 |
||
| for (size_t i = 0; i < text.size(); ++i) { | ||
|
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. 私はこれはどちらでも許容です。状況依存かもしれません。 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 なるほどです!ありがとうございます! |
||
| char c = text[i]; | ||
| characterPositions[c].push_back(i); | ||
| } | ||
| size_t searchPos = 0; | ||
| for (char c : subsequence) { | ||
| auto &positions = characterPositions[c]; | ||
| auto found = | ||
| std::lower_bound(positions.begin(), positions.end(), searchPos); | ||
|
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. おっしゃる通りですね。 step1は尺取り方で解いているのですが、こちらの解法はコメントにもあるとおりFollow Upに対するものになっています。 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. あ、いえ、僕が言っているのはこちらです! philip82148/leetcode-swejp#7 (comment) @usatie さんの回答だと
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. あ、すみません、勘違いしてましたmm |
||
| if (found == positions.end()) { | ||
| return false; | ||
| } | ||
| searchPos = *found; | ||
|
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. 当初は 以下、Solution1〜Solution3はすべて、同じ間違いをしています。 |
||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| // If text is the same all the time, we only need to initialize the data once. | ||
| class Solution2 { | ||
| private: | ||
| std::map<char, std::vector<size_t>> characterPositions; | ||
|
|
||
| public: | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| if (characterPositions.empty()) { | ||
| for (size_t i = 0; i < text.size(); ++i) { | ||
| char c = text[i]; | ||
| characterPositions[c].push_back(i); | ||
| } | ||
| } | ||
|
Comment on lines
+66
to
+71
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. ※講師役の方感覚が違ったら訂正していただきたいです 本当はこういうのはコンストラクタで初期化したいところなんですが、LeetCodeの性質上引数として渡されてしまいます。 if (条件式) initCharacterPositions(text);条件式のところは 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. 確かにその方がいいですね。 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. 副作用のある関数であるという点のほうが気になります。この関数はマルチスレッドで呼ばれた場合に競合状態になる可能性があります。競合状態を避けるため、副作用のある書き方は現実的な範囲でできるだけ避けたほうがよいと思います。また、どうしても副作用のある書き方をしなければならない場合は、適切にロックを取る必要があるかを考慮するのが良いと思います。 |
||
| size_t searchPos = 0; | ||
| for (char c : subsequence) { | ||
| auto &positions = characterPositions[c]; | ||
| auto found = | ||
| std::lower_bound(positions.begin(), positions.end(), searchPos); | ||
| if (found == positions.end()) { | ||
| return false; | ||
| } | ||
| searchPos = *found; | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| // If we expect multiple but small texts, and massive subsequence queries, | ||
| // we can initialize the data for each text. | ||
| class Solution3 { | ||
| private: | ||
| typedef std::map<char, std::vector<size_t>> character_positions_t; | ||
| std::map<std::string, character_positions_t> initialized_data; | ||
| void initialize(const std::string &text) { | ||
| auto &characterPositions = initialized_data[text]; | ||
| for (size_t i = 0; i < text.size(); ++i) { | ||
| char c = text[i]; | ||
| characterPositions[c].push_back(i); | ||
| } | ||
| } | ||
|
|
||
| public: | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| if (initialized_data.count(text) == 0) { | ||
| initialize(text); | ||
| } | ||
|
Comment on lines
+102
to
+104
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.
|
||
| auto &characterPositions = initialized_data[text]; | ||
| size_t searchPos = 0; | ||
| for (char c : subsequence) { | ||
| auto &positions = characterPositions[c]; | ||
| auto found = | ||
| std::lower_bound(positions.begin(), positions.end(), searchPos); | ||
| if (found == positions.end()) { | ||
| return false; | ||
| } | ||
| searchPos = *found; | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| // Dynamic Programming | ||
| class Solution4 { | ||
| public: | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| size_t m = subsequence.size(); | ||
| size_t n = text.size(); | ||
| // is_subseq[i][j] : subsequence[0..i) is a subsequence of text[0..j) | ||
| std::vector<std::vector<bool>> is_subseq(m + 1, | ||
|
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. std::vector については何度か議論があったと思います。それらを意識したうえで使うのであれば大丈夫だと思います。過去のコメントを探してみることをお勧めいたします。 |
||
| std::vector<bool>(n + 1, false)); | ||
| for (size_t j = 0; j <= n; ++j) { | ||
| is_subseq[0][j] = true; | ||
| } | ||
| for (size_t i = 1; i <= m; ++i) { | ||
|
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. レーベンシュタインの編集距離を思い出しました。 |
||
| for (size_t j = 1; j <= n; ++j) { | ||
| if (subsequence[i - 1] == text[j - 1]) { | ||
| is_subseq[i][j] = is_subseq[i - 1][j - 1]; | ||
| } else { | ||
| is_subseq[i][j] = is_subseq[i][j - 1]; | ||
| } | ||
| } | ||
| } | ||
| return is_subseq[m][n]; | ||
| } | ||
| }; | ||
|
|
||
| // Recursive | ||
| class Solution5 { | ||
| public: | ||
| // ラムダでの再帰関数がうまく書けなくて、std::functionを使うことになった | ||
| // 書ける場合と書けない場合の違いは何だろうか? | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| std::function<bool(size_t, size_t)> is_subseq = [&](size_t i, | ||
|
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. ちょっと詳しい方がいたら触れてもらおうと思っていたのですが、もしかしたら触れられずに終わってしまうかもしれないので一応コメントしておきます。 std::functionを使う場合、auto func = ...の場合と違ってキャプチャされた変数を保存するメモリが動的に(ヒープに)確保される可能性があります。 なので使えるときはauto func = ...の形式がいいと思います(なおこれで再帰を書くには引数に渡すしかありません)。 https://stackoverflow.com/questions/46163607/avoid-memory-allocation-with-stdfunction-and-member-function ※良いリファレンスが見つけられずすみません。実装を読むのが早いかもしれません。 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.
型推論に起因する問題な気がしてきました。 ※C++は言語仕様巨大すぎて、どんなにC++学んでも初心者を抜け出せないというミームがあるくらいなので、最初の方はここら辺はあんまり理解していなくてもいいんじゃないかと個人的には思っています。 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. |
||
| size_t j) -> bool { | ||
| if (i == 0) { | ||
| return true; | ||
| } | ||
| if (j == 0) { | ||
| return false; | ||
| } | ||
| if (subsequence[i - 1] == text[j - 1]) { | ||
| return is_subseq(i - 1, j - 1); | ||
| } else { | ||
| return is_subseq(i, j - 1); | ||
| } | ||
| }; | ||
| return is_subseq(subsequence.size(), text.size()); | ||
| } | ||
| }; | ||
|
|
||
| // C++17 way to write recursive lambda | ||
| // Recursive (Lambda), only works with C++17 | ||
| // If auto is used as a type of a parameter or an explicit template parameter | ||
| // list is provided(since C++20), the lambda is a generic lambda. (since C++14) | ||
| // https://en.cppreference.com/w/cpp/language/lambda | ||
| class Solution6 { | ||
| public: | ||
| // 引数で自身を渡してあげれば書けるというのがC++17の機能だった模様 | ||
| // というか、引数でautoを使える(=Generic Lambda)のがC++17から | ||
| // https://github.com/usatie/leetcode/pull/4/files#diff-43e2749181b31eb4f4bf1fd95048e0d7f2fb65e9b44c84eefaf3905a22349a90R77 | ||
| // | ||
| // `auto &&self`というのはどこからか引っ張ってきたコードだったけど、 | ||
| // `auto self`でも`auto &&self`でも動いた. それぞれの挙動の違いが違いが | ||
| // わかっていない. `&`にしないと関数オブジェクト?のコピーが発生するのはわかる | ||
| // 気がするが`&&`は普段使ったことがない. また、cppreferenceのサンプルコードも | ||
| // `auto`だったので、referenceにする必要があるのかもわからない | ||
| // https://stackoverflow.com/questions/29859796/c-auto-vs-auto | ||
| // | ||
| // ChatGPT-o3-mini-highに質問してみて、だんだんと違いがわかってきた。 | ||
| // 色々と理解が曖昧なものがあったが、さらにドキュメントを読む必要がありそう | ||
| // lvalue, rvalue, move constructor, move semantics, perfect forwarding, | ||
| // type erasure, std::function | ||
| // https://chatgpt.com/share/67a67173-839c-8000-913d-ca67b6aa6859 | ||
| // | ||
| // たくさんあるのでひとまず積読ですが、徐々に読んでみます。 | ||
| // https://chatgpt.com/share/67a67173-839c-8000-913d-ca67b6aa6859 | ||
| // https://en.cppreference.com/w/cpp/language/auto | ||
| // https://en.cppreference.com/w/cpp/language/reference | ||
| // https://en.cppreference.com/w/cpp/language/value_category | ||
| // https://en.cppreference.com/w/cpp/utility/move | ||
| // https://en.cppreference.com/w/cpp/language/move_constructor | ||
| // https://en.cppreference.com/w/cpp/language/move_assignment | ||
| // https://en.cppreference.com/w/cpp/utility/forward | ||
| // https://en.cppreference.com/w/cpp/utility/functional/function | ||
| // | ||
| // Type Erasure | ||
| // https://cplusplus.com/articles/oz18T05o/ | ||
| // https://davekilian.com/cpp-type-erasure.html | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| auto is_subseq = [&](auto &&self, size_t i, size_t j) -> bool { | ||
|
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. ラムダ関数にラムダ関数を渡すのはエンジニアのコード(競プロ以外)ではあまり見ないパターンという認識なんですが、どうですかね?? それは気にしない前提で話しますと、ラムダ関数というのは 以下右辺値と左辺値の説明右辺値と左辺値はとてもややこしい問題なので簡単には説明できないです… auto /* resultは左辺値 */ result = /* ここでは右辺値 */ func1(/* ここでは右辺値 */ func2());この違いがあるのは、右辺値は自分しか使わないので破壊したり変更したりしてもいいもの、左辺値は他の人が使う可能性があるので破壊したり変更したりできないもの、みたいなのがざっくりとした説明です。 auto /* selfは右辺値参照だけど左辺値 */ &&self = <右辺値>なので、右辺値参照という左辺値を右辺値として渡すために、move()による変換が必要になります。 self(move(self), ...)より正確な説明は色々記事を見てみるといいと思います 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. はい、大丈夫だと思います。 右辺値参照で渡したほうがラムダのコピーのオーバーヘッドがないので、こうした方が良いのか? 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. あ、すみません、完全に間違えました。 わかります。
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. 自分自身を引数に与えるのは、ラムダ計算の理論的な文脈では見ますが、プロダクションコードで見たことはない気がしますね。 C++23 から explicit object parameter が使えるようで、LeetCode も対応しているようです。 auto を含む lambda は generic lambda なのでユニバーサル参照になるが、使っていないので普通のリファレンスでいいのではということですね。(そもそも、私はあまり複雑なラムダ書きたくないですが、これは古い人だからですね。) 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. あ、そうですね。 |
||
| if (i == 0) { | ||
| return true; | ||
| } | ||
| if (j == 0) { | ||
| return false; | ||
| } | ||
| if (subsequence[i - 1] == text[j - 1]) { | ||
| return self(self, i - 1, j - 1); | ||
| } else { | ||
| return self(self, i, j - 1); | ||
| } | ||
| }; | ||
| return is_subseq(is_subseq, subsequence.size(), text.size()); | ||
| } | ||
| }; | ||
|
|
||
| // C++23 way to write recursive lambda | ||
| // https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_member_functions | ||
| class Solution7 { | ||
| public: | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| auto is_subseq = [&](this auto self, size_t i, size_t j) -> bool { | ||
| if (i == 0) { | ||
| return true; | ||
| } | ||
| if (j == 0) { | ||
| return false; | ||
| } | ||
| if (subsequence[i - 1] == text[j - 1]) { | ||
| return self(i - 1, j - 1); | ||
| } else { | ||
| return self(i, j - 1); | ||
| } | ||
| }; | ||
| return is_subseq(subsequence.size(), text.size()); | ||
| } | ||
| }; | ||
| #endif // STEP2_HPP | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| 3問連続で正解するのにかかった時間 : 6:30 | ||
| subsequence.size() : M | ||
| text.size() : N | ||
| 時間計算量: O(N + kMlogN) | ||
| 空間計算量: O(N) | ||
| */ | ||
| #ifndef STEP3_HPP | ||
| #define STEP3_HPP | ||
|
|
||
| #include <map> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| class Solution { | ||
| private: | ||
| std::map<char, std::vector<int>> character_positions; | ||
|
|
||
| public: | ||
| bool isSubsequence(const std::string &subsequence, const std::string &text) { | ||
| if (character_positions.empty()) { | ||
| for (size_t i = 0; i < text.size(); ++i) { | ||
| char c = text[i]; | ||
| character_positions[c].push_back(i); | ||
| } | ||
| } | ||
| size_t search_pos = 0; | ||
| for (char c : subsequence) { | ||
| auto &positions = character_positions[c]; | ||
| auto found = | ||
| std::lower_bound(positions.begin(), positions.end(), search_pos); | ||
| if (found == positions.end()) { | ||
| return false; | ||
| } | ||
| search_pos = *found; | ||
| } | ||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| #endif // STEP3_HPP |
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.
個人用なので気にしてないとかだったらすみません
ターゲット(コロンの左側)がファイル名ではない場合は以下のようにするといいです。
ターゲットが疑似ターゲットでファイルでないことを示します(runもファイルでないので同じようにします)
(また、一番上のターゲットはデフォルトターゲットで
makeだけで実行できるので(このような練習用リポジトリだと僕だったらrunを一番上にします(もしくは.DEFAULT_GOALを指定することでもできそう)))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.
ありがとうございます。おっしゃる通り、.PHONY等は省略しています。
また、実行は明示的に行いたいので、自分は一番上にはしないことにしています。