From 6138b56ff3126e517b1aef1da1b0e2f46e1835fa Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Wed, 5 Feb 2025 12:35:36 -0800 Subject: [PATCH 1/9] Step1 of [392. Is Subsequence](https://leetcode.com/problems/is-subsequence/) --- Arai60/52. Is Subsequence/main.cpp | 24 ++++++++++++++++++++ Arai60/52. Is Subsequence/step1.hpp | 35 +++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Arai60/52. Is Subsequence/step1.hpp diff --git a/Arai60/52. Is Subsequence/main.cpp b/Arai60/52. Is Subsequence/main.cpp index e69de29..4d398c2 100644 --- a/Arai60/52. Is Subsequence/main.cpp +++ b/Arai60/52. Is Subsequence/main.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include "step1.hpp" + +#define test(subsequence, text, expected) \ + [] { \ + bool actual = Solution().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); +} diff --git a/Arai60/52. Is Subsequence/step1.hpp b/Arai60/52. Is Subsequence/step1.hpp new file mode 100644 index 0000000..28f55a9 --- /dev/null +++ b/Arai60/52. Is Subsequence/step1.hpp @@ -0,0 +1,35 @@ +#ifndef STEP1_HPP +#define STEP1_HPP + +/* + 何がわからなかったか + - N/A + 何を考えて解いていたか + - tを前から舐めていけばいい + 正解してから気づいたこと + - Follow upに対応するためには、tを毎回舐めると無駄なので、前処理をしておいて + ある文字がtのなかのどこにあるかを高速に調べられるようにしておくといい +*/ +#include + +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 From 32ef7f1c326488057d9914102d527770190f2d4f Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Thu, 6 Feb 2025 12:26:24 -0800 Subject: [PATCH 2/9] Add step2.hpp --- Arai60/52. Is Subsequence/main.cpp | 4 +- Arai60/52. Is Subsequence/step2.hpp | 111 ++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 Arai60/52. Is Subsequence/step2.hpp diff --git a/Arai60/52. Is Subsequence/main.cpp b/Arai60/52. Is Subsequence/main.cpp index 4d398c2..db83e67 100644 --- a/Arai60/52. Is Subsequence/main.cpp +++ b/Arai60/52. Is Subsequence/main.cpp @@ -1,11 +1,11 @@ #include #include -#include "step1.hpp" +#include "step2.hpp" #define test(subsequence, text, expected) \ [] { \ - bool actual = Solution().isSubsequence(subsequence, text); \ + bool actual = Solution3().isSubsequence(subsequence, text); \ std::cout << "Test: " << #subsequence << " in " << #text << "\" : "; \ if (actual == expected) { \ std::cout << "OK" << std::endl; \ diff --git a/Arai60/52. Is Subsequence/step2.hpp b/Arai60/52. Is Subsequence/step2.hpp new file mode 100644 index 0000000..aa7c5b0 --- /dev/null +++ b/Arai60/52. Is Subsequence/step2.hpp @@ -0,0 +1,111 @@ +/* + 講師陣はどのようなコメントを残すだろうか? + - + 他の人のコードを読んで考えたこと + - + 改善する時にかんがえたこと + - 同じtextに対してqueryが来ないなら初期化したcharacterPositionsをメンバ変数で + 持ってもいいし、Constructorで初期化してもいい。 + - Constructorで初期化する場合関数プロトタイプが変わってテストをそのためだけに + 書き直したり用意するのが面倒なのでここではやってない。 + - 複数のtextに対してsubsequenceをチェックする場合、textごとに初期化する。 + ただし、textが大きい場合はmapのkeyとしてtextも保存する羽目になるので、 + メモリを食ってしまうかもしれない。衝突を許容して少ない数のtextだったら + key自体もhashにしてしまってもいいかもしれない? +*/ +#ifndef STEP2_HPP +#define STEP2_HPP + +#include +#include +#include + +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> characterPositions; + for (size_t i = 0; i < text.size(); ++i) { + 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); + if (found == positions.end()) { + return false; + } + searchPos = *found; + } + return true; + } +}; + +// If text is the same all the time, we only need to initialize the data once. +class Solution2 { +private: + std::map> 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); + } + } + 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> character_positions_t; + std::map 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); + } + 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; + } +}; + +#endif // STEP2_HPP From 7d79512cdc0107a9bce8fffe8f357b3a471d7c34 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Thu, 6 Feb 2025 12:26:35 -0800 Subject: [PATCH 3/9] Add Makefile --- Arai60/52. Is Subsequence/Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Arai60/52. Is Subsequence/Makefile diff --git a/Arai60/52. Is Subsequence/Makefile b/Arai60/52. Is Subsequence/Makefile new file mode 100644 index 0000000..e2aa945 --- /dev/null +++ b/Arai60/52. Is Subsequence/Makefile @@ -0,0 +1,12 @@ +NAME = a.out +SRC = main.cpp +CXX = g++ +CXXFLAGS = -Wall -Wextra -Werror -std=c++11 + +all: $(NAME) + +$(NAME): $(SRC) step1.hpp step2.hpp step3.hpp + $(CXX) -o $(NAME) $(SRC) $(CXXFLAGS) + +run: $(NAME) + ./$(NAME) From f56e91e6605cb292ae409de8aead263fe72b930b Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Thu, 6 Feb 2025 16:03:54 -0800 Subject: [PATCH 4/9] [wip] Step2 --- Arai60/52. Is Subsequence/step2.hpp | 66 +++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/Arai60/52. Is Subsequence/step2.hpp b/Arai60/52. Is Subsequence/step2.hpp index aa7c5b0..1e0b5e7 100644 --- a/Arai60/52. Is Subsequence/step2.hpp +++ b/Arai60/52. Is Subsequence/step2.hpp @@ -2,7 +2,13 @@ 講師陣はどのようなコメントを残すだろうか? - 他の人のコードを読んで考えたこと - - + - 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で初期化してもいい。 @@ -12,6 +18,8 @@ ただし、textが大きい場合はmapのkeyとしてtextも保存する羽目になるので、 メモリを食ってしまうかもしれない。衝突を許容して少ない数のtextだったら key自体もhashにしてしまってもいいかもしれない? + - `auto positions = characterPositions[c];`と元々はしていたけれど + referenceにしておかないと意図せぬcopyが発生してしまう */ #ifndef STEP2_HPP #define STEP2_HPP @@ -35,7 +43,7 @@ class Solution1 { } size_t searchPos = 0; for (char c : subsequence) { - auto positions = characterPositions[c]; + auto &positions = characterPositions[c]; auto found = std::lower_bound(positions.begin(), positions.end(), searchPos); if (found == positions.end()) { @@ -62,7 +70,7 @@ class Solution2 { } size_t searchPos = 0; for (char c : subsequence) { - auto positions = characterPositions[c]; + auto &positions = characterPositions[c]; auto found = std::lower_bound(positions.begin(), positions.end(), searchPos); if (found == positions.end()) { @@ -96,7 +104,7 @@ class Solution3 { auto &characterPositions = initialized_data[text]; size_t searchPos = 0; for (char c : subsequence) { - auto positions = characterPositions[c]; + auto &positions = characterPositions[c]; auto found = std::lower_bound(positions.begin(), positions.end(), searchPos); if (found == positions.end()) { @@ -108,4 +116,54 @@ class Solution3 { } }; +// 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> is_subseq(m + 1, + std::vector(n + 1, false)); + for (size_t j = 0; j <= n; ++j) { + is_subseq[0][j] = true; + } + for (size_t i = 1; i <= m; ++i) { + for (size_t j = 1; j <= n; ++j) { + if (subsequence[i] == text[j]) { + 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を使うことになった + // 書ける場合と書けない場合の違いは何だろうか? + // https://github.com/usatie/leetcode/pull/4/files#diff-43e2749181b31eb4f4bf1fd95048e0d7f2fb65e9b44c84eefaf3905a22349a90R77 + bool isSubsequence(const std::string &subsequence, const std::string &text) { + std::function is_subseq; + is_subseq = [&](size_t i, size_t j) -> bool { + if (i == 0) { + return true; + } + if (j == 0) { + return false; + } + if (subsequence[i] == text[j]) { + return is_subseq(i - 1, j - 1); + } else { + return is_subseq(i, j - 1); + } + }; + return is_subseq(subsequence.size(), text.size()); + } +}; + #endif // STEP2_HPP From b430054727f007678809f1f2d7c2719b4cd53605 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Thu, 6 Feb 2025 16:04:04 -0800 Subject: [PATCH 5/9] [wip] Step 3 --- Arai60/52. Is Subsequence/main.cpp | 2 +- Arai60/52. Is Subsequence/step3.hpp | 41 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Arai60/52. Is Subsequence/step3.hpp diff --git a/Arai60/52. Is Subsequence/main.cpp b/Arai60/52. Is Subsequence/main.cpp index db83e67..8cb02a3 100644 --- a/Arai60/52. Is Subsequence/main.cpp +++ b/Arai60/52. Is Subsequence/main.cpp @@ -5,7 +5,7 @@ #define test(subsequence, text, expected) \ [] { \ - bool actual = Solution3().isSubsequence(subsequence, text); \ + bool actual = Solution5().isSubsequence(subsequence, text); \ std::cout << "Test: " << #subsequence << " in " << #text << "\" : "; \ if (actual == expected) { \ std::cout << "OK" << std::endl; \ diff --git a/Arai60/52. Is Subsequence/step3.hpp b/Arai60/52. Is Subsequence/step3.hpp new file mode 100644 index 0000000..c84eb3b --- /dev/null +++ b/Arai60/52. Is Subsequence/step3.hpp @@ -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 +#include +#include + +class Solution { +private: + std::map> 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 From c59dc6371743827b1943e6902ec42ba261fdc9cd Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Thu, 6 Feb 2025 16:07:43 -0800 Subject: [PATCH 6/9] [wip] Step2 memo about lambda and std::function --- Arai60/52. Is Subsequence/step2.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Arai60/52. Is Subsequence/step2.hpp b/Arai60/52. Is Subsequence/step2.hpp index 1e0b5e7..44b0eb3 100644 --- a/Arai60/52. Is Subsequence/step2.hpp +++ b/Arai60/52. Is Subsequence/step2.hpp @@ -146,10 +146,10 @@ class Solution5 { public: // ラムダでの再帰関数がうまく書けなくて、std::functionを使うことになった // 書ける場合と書けない場合の違いは何だろうか? + // 引数で自身を渡してあげれば書けるというのがC++17の機能だった模様 // https://github.com/usatie/leetcode/pull/4/files#diff-43e2749181b31eb4f4bf1fd95048e0d7f2fb65e9b44c84eefaf3905a22349a90R77 bool isSubsequence(const std::string &subsequence, const std::string &text) { - std::function is_subseq; - is_subseq = [&](size_t i, size_t j) -> bool { + auto is_subseq = [&](size_t i, size_t j) -> bool { if (i == 0) { return true; } From 2482631506af897ed8e47eaa0ff3c0035b9ab399 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Fri, 7 Feb 2025 12:18:30 -0800 Subject: [PATCH 7/9] More recursive lambda implementations with C++17 and C++23 --- Arai60/52. Is Subsequence/step2.hpp | 57 +++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/Arai60/52. Is Subsequence/step2.hpp b/Arai60/52. Is Subsequence/step2.hpp index 44b0eb3..7fb2495 100644 --- a/Arai60/52. Is Subsequence/step2.hpp +++ b/Arai60/52. Is Subsequence/step2.hpp @@ -24,6 +24,7 @@ #ifndef STEP2_HPP #define STEP2_HPP +#include #include #include #include @@ -146,10 +147,10 @@ class Solution5 { public: // ラムダでの再帰関数がうまく書けなくて、std::functionを使うことになった // 書ける場合と書けない場合の違いは何だろうか? - // 引数で自身を渡してあげれば書けるというのがC++17の機能だった模様 - // https://github.com/usatie/leetcode/pull/4/files#diff-43e2749181b31eb4f4bf1fd95048e0d7f2fb65e9b44c84eefaf3905a22349a90R77 + // https://en.cppreference.com/w/cpp/language/lambda bool isSubsequence(const std::string &subsequence, const std::string &text) { - auto is_subseq = [&](size_t i, size_t j) -> bool { + std::function is_subseq = [&](size_t i, + size_t j) -> bool { if (i == 0) { return true; } @@ -166,4 +167,54 @@ class Solution5 { } }; +// C++17 way to write recursive lambda +// Recursive (Lambda), only works with C++17 +class Solution6 { +public: + // 引数で自身を渡してあげれば書けるというのがC++17の機能だった模様 + // https://github.com/usatie/leetcode/pull/4/files#diff-43e2749181b31eb4f4bf1fd95048e0d7f2fb65e9b44c84eefaf3905a22349a90R77 + // + // `auto &&self`というのはどこからか引っ張ってきたコードだったけど、 + // `auto self`でも`auto &&self`でも動いた. それぞれの挙動の違いが違いが + // わかっていない. `&`にしないと関数オブジェクト?のコピーが発生するのはわかる + // 気がするが`&&`は普段使ったことがない. また、cppreferenceのサンプルコードも + // `auto`だったので、referenceにする必要があるのかもわからない + bool isSubsequence(const std::string &subsequence, const std::string &text) { + auto is_subseq = [&](auto self, size_t i, size_t j) -> bool { + if (i == 0) { + return true; + } + if (j == 0) { + return false; + } + if (subsequence[i] == text[j]) { + 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 +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] == text[j]) { + return self(i - 1, j - 1); + } else { + return self(i, j - 1); + } + }; + return is_subseq(subsequence.size(), text.size()); + } +}; #endif // STEP2_HPP From 44c5d15a71864a58c9cc5f43db5a43b2b92dc144 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Fri, 7 Feb 2025 16:20:06 -0800 Subject: [PATCH 8/9] Add more recursive lambda examples --- Arai60/52. Is Subsequence/Makefile | 2 +- Arai60/52. Is Subsequence/main.cpp | 2 +- Arai60/52. Is Subsequence/step2.hpp | 30 +++++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Arai60/52. Is Subsequence/Makefile b/Arai60/52. Is Subsequence/Makefile index e2aa945..3514687 100644 --- a/Arai60/52. Is Subsequence/Makefile +++ b/Arai60/52. Is Subsequence/Makefile @@ -1,7 +1,7 @@ NAME = a.out SRC = main.cpp CXX = g++ -CXXFLAGS = -Wall -Wextra -Werror -std=c++11 +CXXFLAGS = -Wall -Wextra -Werror -std=c++23 all: $(NAME) diff --git a/Arai60/52. Is Subsequence/main.cpp b/Arai60/52. Is Subsequence/main.cpp index 8cb02a3..6f5010b 100644 --- a/Arai60/52. Is Subsequence/main.cpp +++ b/Arai60/52. Is Subsequence/main.cpp @@ -5,7 +5,7 @@ #define test(subsequence, text, expected) \ [] { \ - bool actual = Solution5().isSubsequence(subsequence, text); \ + bool actual = Solution7().isSubsequence(subsequence, text); \ std::cout << "Test: " << #subsequence << " in " << #text << "\" : "; \ if (actual == expected) { \ std::cout << "OK" << std::endl; \ diff --git a/Arai60/52. Is Subsequence/step2.hpp b/Arai60/52. Is Subsequence/step2.hpp index 7fb2495..ba3349a 100644 --- a/Arai60/52. Is Subsequence/step2.hpp +++ b/Arai60/52. Is Subsequence/step2.hpp @@ -147,7 +147,6 @@ class Solution5 { public: // ラムダでの再帰関数がうまく書けなくて、std::functionを使うことになった // 書ける場合と書けない場合の違いは何だろうか? - // https://en.cppreference.com/w/cpp/language/lambda bool isSubsequence(const std::string &subsequence, const std::string &text) { std::function is_subseq = [&](size_t i, size_t j) -> bool { @@ -169,9 +168,13 @@ class Solution5 { // 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`というのはどこからか引っ張ってきたコードだったけど、 @@ -179,8 +182,30 @@ class Solution6 { // わかっていない. `&`にしないと関数オブジェクト?のコピーが発生するのはわかる // 気がするが`&&`は普段使ったことがない. また、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 { + auto is_subseq = [&](auto &&self, size_t i, size_t j) -> bool { if (i == 0) { return true; } @@ -198,6 +223,7 @@ class Solution6 { }; // 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) { From db0790afcbe0e57e141f025f902c1226890976b6 Mon Sep 17 00:00:00 2001 From: Shun Usami Date: Fri, 7 Feb 2025 16:34:28 -0800 Subject: [PATCH 9/9] Fix the empty string case in DP/recursive solutions --- Arai60/52. Is Subsequence/main.cpp | 3 ++- Arai60/52. Is Subsequence/step2.hpp | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Arai60/52. Is Subsequence/main.cpp b/Arai60/52. Is Subsequence/main.cpp index 6f5010b..63d9b11 100644 --- a/Arai60/52. Is Subsequence/main.cpp +++ b/Arai60/52. Is Subsequence/main.cpp @@ -5,7 +5,7 @@ #define test(subsequence, text, expected) \ [] { \ - bool actual = Solution7().isSubsequence(subsequence, text); \ + bool actual = Solution4().isSubsequence(subsequence, text); \ std::cout << "Test: " << #subsequence << " in " << #text << "\" : "; \ if (actual == expected) { \ std::cout << "OK" << std::endl; \ @@ -21,4 +21,5 @@ int main(void) { test("axc", "ahbgdc", false); test("", "ahbgdc", true); test("a", "", false); + test("a", "b", false); } diff --git a/Arai60/52. Is Subsequence/step2.hpp b/Arai60/52. Is Subsequence/step2.hpp index ba3349a..71743d0 100644 --- a/Arai60/52. Is Subsequence/step2.hpp +++ b/Arai60/52. Is Subsequence/step2.hpp @@ -131,7 +131,7 @@ class Solution4 { } for (size_t i = 1; i <= m; ++i) { for (size_t j = 1; j <= n; ++j) { - if (subsequence[i] == text[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]; @@ -156,7 +156,7 @@ class Solution5 { if (j == 0) { return false; } - if (subsequence[i] == text[j]) { + if (subsequence[i - 1] == text[j - 1]) { return is_subseq(i - 1, j - 1); } else { return is_subseq(i, j - 1); @@ -212,7 +212,7 @@ class Solution6 { if (j == 0) { return false; } - if (subsequence[i] == text[j]) { + if (subsequence[i - 1] == text[j - 1]) { return self(self, i - 1, j - 1); } else { return self(self, i, j - 1); @@ -234,7 +234,7 @@ class Solution7 { if (j == 0) { return false; } - if (subsequence[i] == text[j]) { + if (subsequence[i - 1] == text[j - 1]) { return self(i - 1, j - 1); } else { return self(i, j - 1);