diff --git a/README.md b/README.md new file mode 100644 index 0000000..bd9546d --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Competitive Programming C Plus Plus Library + +A C++ library for competitive programming that includes a wide range of algorithms and data structures. Additionally, the project provides tests to ensure the correctness of its implementations. + diff --git a/competitive_programming/scripts/test.sh b/competitive_programming/scripts/test.sh index ff4b233..66ed751 100644 --- a/competitive_programming/scripts/test.sh +++ b/competitive_programming/scripts/test.sh @@ -4,8 +4,12 @@ set -e BUILD_DIR=build -echo "==> Compilando" -cmake --build $BUILD_DIR - -echo "==> Rodando testes" -ctest --test-dir $BUILD_DIR \ No newline at end of file +if [ -d $BUILD_DIR ]; then + echo "==> Compilando" + cmake --build $BUILD_DIR + + echo "==> Rodando testes" + ctest --test-dir $BUILD_DIR +else + echo "o diretório $BUILD_DIR não existe" +fi \ No newline at end of file diff --git a/competitive_programming/src/data_structures/disjoint_set.hpp b/competitive_programming/src/data_structures/disjoint_set.hpp index 007dc0b..54baec4 100644 --- a/competitive_programming/src/data_structures/disjoint_set.hpp +++ b/competitive_programming/src/data_structures/disjoint_set.hpp @@ -10,6 +10,9 @@ #include #include +namespace data_structures +{ + class DisjointSet { public: @@ -82,4 +85,6 @@ class DisjointSet /* the size of each disjoint set */ std::vector _size; -}; \ No newline at end of file +}; + +} diff --git a/competitive_programming/src/data_structures/fenwick_tree.hpp b/competitive_programming/src/data_structures/fenwick_tree.hpp index 8d62f8c..08d26a1 100644 --- a/competitive_programming/src/data_structures/fenwick_tree.hpp +++ b/competitive_programming/src/data_structures/fenwick_tree.hpp @@ -12,8 +12,10 @@ #include #include +namespace data_structures +{ template -requires std::regular_invocable && std::same_as, T> +requires std::regular_invocable && std::convertible_to, T> class FenwickTree { public: @@ -23,7 +25,7 @@ class FenwickTree * @param op the binary operator that calculates the result * @param initial the default value that will be used when there is not value */ - FenwickTree(std::size_t n, Op&& op, T initial): + FenwickTree(std::size_t n, const Op& op, T initial): _ft(n + 1, initial), _op(op), _initial(initial) @@ -81,4 +83,6 @@ template auto make_fenwick_tree(std::size_t n, Op&& op, T initial) { return FenwickTree>(n, std::forward(op), initial); +} + } \ No newline at end of file diff --git a/competitive_programming/src/data_structures/segment_tree.hpp b/competitive_programming/src/data_structures/segment_tree.hpp index 7d6c415..88566f4 100644 --- a/competitive_programming/src/data_structures/segment_tree.hpp +++ b/competitive_programming/src/data_structures/segment_tree.hpp @@ -6,6 +6,9 @@ #include #include +namespace data_structures +{ + /** * @brief Segtree traits concepts with method neutral that returns the neutral * element and merge that returns the result of merging the results of children node @@ -119,4 +122,6 @@ class SegTree /** The container of nodes */ std::vector _container; -}; \ No newline at end of file +}; + +} \ No newline at end of file diff --git a/competitive_programming/src/data_structures/sparse_table.hpp b/competitive_programming/src/data_structures/sparse_table.hpp index 4baeadc..fba35e6 100644 --- a/competitive_programming/src/data_structures/sparse_table.hpp +++ b/competitive_programming/src/data_structures/sparse_table.hpp @@ -13,8 +13,13 @@ #include #include +namespace data_structures +{ + template -requires std::regular_invocable && std::same_as, T> +requires std::regular_invocable +&& std::convertible_to, T> +&& std::copy_constructible class SparseTable { public: @@ -25,8 +30,8 @@ class SparseTable * @param op the binary function that calculates the answer */ template - requires std::same_as::value_type, T> - SparseTable(It begin, It end, F&& op): + requires std::convertible_to::value_type, T> + SparseTable(It begin, It end, const F& op): _op(op) { std::size_t n = std::distance(begin, end); @@ -103,8 +108,10 @@ class SparseTable * @param op the binary function that calculates the answer */ template -auto make_sparse_table(It begin, It end, F&& op) +inline auto make_sparse_table(It begin, It end, F&& op) { using T = typename std::iterator_traits::value_type; return SparseTable>(begin, end, std::forward(op)); +} + } \ No newline at end of file diff --git a/competitive_programming/src/math/mint.hpp b/competitive_programming/src/math/mint.hpp index 5afb50d..1ef38a4 100644 --- a/competitive_programming/src/math/mint.hpp +++ b/competitive_programming/src/math/mint.hpp @@ -118,7 +118,7 @@ class mint constexpr bool operator!=(const mint& rhs) const noexcept { - return !(val == rhs.val); + return !(*this == rhs); } template diff --git a/competitive_programming/src/math/pollard_rho.hpp b/competitive_programming/src/math/pollard_rho.hpp index 0f5b349..df5f976 100644 --- a/competitive_programming/src/math/pollard_rho.hpp +++ b/competitive_programming/src/math/pollard_rho.hpp @@ -5,10 +5,44 @@ #include #include #include +#include +#include namespace math::factorization { +/** + * @brief Compute the greatest common divisor of two numbers + * @param a a number + * @param b a number + * @return the greatest common divisor of a and b + * @note This function is necessary because std::gcd does not support __int128 + * numbers, which are used in the factorization process. + */ +__int128 gcd(__int128 a, __int128 b) +{ + while (b != 0) + { + auto temp = b; + b = a % b; + a = temp; + } + + return a; +} + +/** + * @brief Compute the absolute value of a number + * @param x a number + * @return the absolute value of x + * @note This function is necessary because std::abs does not support __int128 + * numbers, which are used in the factorization process. + */ +constexpr __int128 abs(__int128 x) +{ + return x < 0 ? -x : x; +} + /** * @brief Take the modulo of the mutiplication of two numbers * @param a a number @@ -115,7 +149,15 @@ inline T rho(T n) { x = f(x, c, n); y = f(f(y, c, n), c, n); - g = gcd(abs(x - y), n); + + if constexpr(std::is_same_v) + { + g = gcd(abs(x - y), n); + } + else + { + g = std::gcd(std::abs(x - y), n); + } } } diff --git a/competitive_programming/src/string/kmp.hpp b/competitive_programming/src/string/kmp.hpp index 68c7726..4d8cb63 100644 --- a/competitive_programming/src/string/kmp.hpp +++ b/competitive_programming/src/string/kmp.hpp @@ -8,6 +8,10 @@ namespace strings { inline std::vector kmp(const std::string& s) { int n = s.size(); + + if(n == 0) + return {}; + std::vector p(n); p[0] = 0; for(int i = 1; i < n; ++i) { diff --git a/competitive_programming/test/data_structures/CMakeLists.txt b/competitive_programming/test/data_structures/CMakeLists.txt index e69de29..46c3dba 100644 --- a/competitive_programming/test/data_structures/CMakeLists.txt +++ b/competitive_programming/test/data_structures/CMakeLists.txt @@ -0,0 +1,26 @@ +# Disjoint Set +add_executable(disjoint-set disjoint_set.cpp) +target_include_directories(disjoint-set PRIVATE ${PROJECT_INCLUDE_DIR}) +target_link_libraries(disjoint-set PRIVATE GTest::gtest GTest::gtest_main) + +# Sparse Table +add_executable(sparse-table sparse_table.cpp) +target_include_directories(sparse-table PRIVATE ${PROJECT_INCLUDE_DIR}) +target_link_libraries(sparse-table PRIVATE GTest::gtest GTest::gtest_main) + +# Fenwick Tree +add_executable(fenwick-tree fenwick_tree.cpp) +target_include_directories(fenwick-tree PRIVATE ${PROJECT_INCLUDE_DIR}) +target_link_libraries(fenwick-tree PRIVATE GTest::gtest GTest::gtest_main) + +# Segment Tree +add_executable(segment-tree segment_tree.cpp) +target_include_directories(segment-tree PRIVATE ${PROJECT_INCLUDE_DIR}) +target_link_libraries(segment-tree PRIVATE GTest::gtest GTest::gtest_main) + +include(GoogleTest) + +gtest_discover_tests(disjoint-set) +gtest_discover_tests(sparse-table) +gtest_discover_tests(fenwick-tree) +gtest_discover_tests(segment-tree) diff --git a/competitive_programming/test/data_structures/disjoint_set.cpp b/competitive_programming/test/data_structures/disjoint_set.cpp new file mode 100644 index 0000000..fce1575 --- /dev/null +++ b/competitive_programming/test/data_structures/disjoint_set.cpp @@ -0,0 +1,82 @@ +#include + +#include "data_structures/disjoint_set.hpp" + +TEST(DisjointSet, DisconnectedGraphTest) +{ + constexpr std::size_t N = 10; + + data_structures::DisjointSet uf(N); + + for(std::size_t u = 1; u < N; ++u) + for(std::size_t v = 0; v < u; ++v) + EXPECT_FALSE(uf.is_same(u, v)); + + for(std::size_t u = 0; u < N; ++u) + { + EXPECT_EQ(uf.findSet(u), u); + EXPECT_EQ(uf.getSize(u), 1u); + } +} + +TEST(DisjointSet, PathTest) +{ + constexpr std::size_t N = 10; + + data_structures::DisjointSet uf(N); + + for(std::size_t u = 1; u < N; ++u) + uf.unite(0, u); + + const auto root = uf.findSet(0); + + for(std::size_t u = 0; u < N; ++u) + { + EXPECT_EQ(uf.findSet(u), root); + EXPECT_EQ(uf.getSize(u), N); + } +} + +TEST(DisjointSet, CompleteGraphTest) +{ + constexpr std::size_t N = 10; + + data_structures::DisjointSet uf(N); + + for(std::size_t u = 1; u < N; ++u) + for(std::size_t v = 0; v < u; ++v) + uf.unite(u, v); + + for(std::size_t u = 1; u < N; ++u) + for(std::size_t v = 0; v < u; ++v) + EXPECT_TRUE(uf.is_same(u, v)); + + const auto root = uf.findSet(0); + + for(std::size_t u = 0; u < N; ++u) + { + EXPECT_EQ(uf.findSet(u), root); + EXPECT_EQ(uf.getSize(u), N); + } +} + +TEST(DisjointSet, SplittedPathsTest) +{ + constexpr std::size_t N = 10; + + data_structures::DisjointSet uf(N); + + for(std::size_t u = 2; u < N; ++u) + uf.unite(u % 2, u); + + const std::size_t root[] = {uf.findSet(0), uf.findSet(1)}; + + EXPECT_NE(root[0], root[1]); + + for(std::size_t u = 0; u < N; ++u) + { + EXPECT_EQ(uf.findSet(u), root[u % 2]); + EXPECT_EQ(uf.getSize(u), N / 2); + } +} + diff --git a/competitive_programming/test/data_structures/fenwick_tree.cpp b/competitive_programming/test/data_structures/fenwick_tree.cpp new file mode 100644 index 0000000..6494a43 --- /dev/null +++ b/competitive_programming/test/data_structures/fenwick_tree.cpp @@ -0,0 +1,42 @@ +#include + +#include "data_structures/fenwick_tree.hpp" +#include +#include +#include +#include + +TEST(FenwickTree, SumTest) +{ + constexpr std::size_t N = 10; + + auto ft = data_structures::make_fenwick_tree(N, std::plus(), 0); + + for(std::size_t i = 1; i <= N; ++i) + ft.update(i, i); + + for(std::size_t i = 1; i <= N; ++i) + { + EXPECT_EQ(ft.query(i), i * (i + 1) / 2); + + for(std::size_t j = 1; j < i; ++j) + EXPECT_EQ(ft.query(i) - ft.query(j - 1), (i + j) * (i - j + 1) / 2); + } +} + +TEST(FenwickTree, MaxPrefixTest) +{ + constexpr std::size_t N = 10; + + const auto max = [](const auto& lhs, const auto& rhs) { + return std::max(lhs, rhs); + }; + + auto ft = data_structures::make_fenwick_tree(N, max, std::numeric_limits::min()); + + for(std::size_t i = 1; i <= N; ++i) + ft.update(i, i); + + for(std::size_t i = 1; i <= N; ++i) + EXPECT_EQ(ft.query(i), static_cast(i)); +} \ No newline at end of file diff --git a/competitive_programming/test/data_structures/segment_tree.cpp b/competitive_programming/test/data_structures/segment_tree.cpp new file mode 100644 index 0000000..7850814 --- /dev/null +++ b/competitive_programming/test/data_structures/segment_tree.cpp @@ -0,0 +1,102 @@ +#include + +#include "data_structures/segment_tree.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace data_structures; + +struct SumTraits +{ + using value_type = int; + + static value_type merge(const value_type& lhs, const value_type& rhs) + { + return lhs + rhs; + } + + static value_type neutral() + { + return 0; + } +}; + +struct MinTraits +{ + using value_type = int; + + static value_type merge(const value_type& lhs, const value_type& rhs) + { + return std::min(lhs, rhs); + } + + static value_type neutral() + { + return std::numeric_limits::max(); + } +}; + +TEST(SegmentTree, SumTest) +{ + constexpr std::size_t N = 50; + + auto view = std::views::iota(1, 1 + static_cast(N)); + + std::vector vec; + std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); + + vec.reserve(N); + + for(const auto& value : view) + vec.push_back(value); + + std::shuffle(vec.begin(), vec.end(), rng); + + SegTree st(vec); + + for(std::size_t i = 0; i < N; ++i) + { + for(std::size_t j = 0; j <= i; ++j) + { + auto sum = std::accumulate(vec.begin() + j, vec.begin() + i + 1, 0); + + EXPECT_EQ(st.query(j, i), sum); + } + } +} + +TEST(SegmentTree, MinTest) +{ + constexpr std::size_t N = 50; + + auto view = std::views::iota(1, 1 + static_cast(N)); + + std::vector vec; + std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); + + vec.reserve(N); + + for(const auto& value : view) + vec.push_back(value); + + std::shuffle(vec.begin(), vec.end(), rng); + + SegTree st(vec); + + for(std::size_t i = 0; i < N; ++i) + { + for(std::size_t j = 0; j <= i; ++j) + { + auto min = std::reduce(vec.begin() + j, vec.begin() + i + 1, std::numeric_limits::max(), [](const auto& acc, const auto& value) { + return std::min(acc, value); + }); + + EXPECT_EQ(st.query(j, i), min); + } + } +} \ No newline at end of file diff --git a/competitive_programming/test/data_structures/sparse_table.cpp b/competitive_programming/test/data_structures/sparse_table.cpp new file mode 100644 index 0000000..ee04b82 --- /dev/null +++ b/competitive_programming/test/data_structures/sparse_table.cpp @@ -0,0 +1,78 @@ +#include + +#include "data_structures/sparse_table.hpp" + +#include +#include +#include +#include +#include + + +TEST(SparseTable, RMQTest) +{ + constexpr auto INF = std::numeric_limits::max(); + constexpr std::size_t N = 50; + + std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); + std::uniform_int_distribution uid(0, INF); + + const auto view = std::views::iota(std::size_t{}, N) | std::views::transform([&uid, &rng](auto) { + return uid(rng); + }); + + std::vector vec; + + vec.reserve(N); + + for(const auto& value : view) + vec.push_back(value); + + auto op = [](const auto& lhs, const auto& rhs) { + return std::min(lhs, rhs); + }; + + const auto sp = data_structures::make_sparse_table(std::ranges::begin(vec), std::ranges::end(vec), op); + + for(std::size_t l = 0; l < N; ++l) + { + for(std::size_t r = l; r < N; ++r) + { + const auto min = std::reduce(vec.begin() + l, vec.begin() + r + 1, INF, op); + + EXPECT_EQ(sp.query(l, r), min); + } + } +} + +TEST(SparseTable, LogQueryTest) +{ + constexpr int MAXN = 1'000'000; + constexpr std::size_t N = 50; + + std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count()); + std::uniform_int_distribution uid(0, MAXN); + + const auto view = std::views::iota(std::size_t{}, N) | std::views::transform([&uid, &rng](auto) { + return uid(rng); + }); + + std::vector vec; + + vec.reserve(N); + + for(const auto& value : view) + vec.push_back(value); + + const auto sp = data_structures::make_sparse_table(std::ranges::begin(vec), std::ranges::end(vec), std::plus()); + + for(std::size_t l = 0; l < N; ++l) + { + for(std::size_t r = l; r < N; ++r) + { + const auto sum = std::accumulate(vec.begin() + l, vec.begin() + r + 1, 0); + + EXPECT_EQ(sp.query(0, l, r), sum); + } + } +} \ No newline at end of file diff --git a/competitive_programming/test/graph/CMakeLists.txt b/competitive_programming/test/graph/CMakeLists.txt index e69de29..2fc3cff 100644 --- a/competitive_programming/test/graph/CMakeLists.txt +++ b/competitive_programming/test/graph/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(tree-center tree_center.cpp) + +target_include_directories(tree-center PRIVATE ${PROJECT_INCLUDE_DIR}) + +target_link_libraries(tree-center PRIVATE GTest::gtest GTest::gtest_main) + +include(GoogleTest) + +gtest_discover_tests(tree-center) \ No newline at end of file diff --git a/competitive_programming/test/graph/tree_center.cpp b/competitive_programming/test/graph/tree_center.cpp new file mode 100644 index 0000000..56b88e7 --- /dev/null +++ b/competitive_programming/test/graph/tree_center.cpp @@ -0,0 +1,117 @@ +#include + +#include "graph/tree_center.hpp" + +#include + +class GraphFixture : public ::testing::Test { +protected: + std::vector> adj; + + void SetUp() override + { + + } + + void TearDown() override + { + adj.clear(); + } + + void initialize(int n) + { + adj.resize(n); + } + + void add_edge(int u, int v) + { + adj[u].push_back(v); + adj[v].push_back(u); + } +}; + +TEST_F(GraphFixture, StarTreeTest) +{ + const std::vector expectedCenter {0}; + const int expectedDiameter {2}; + + initialize(5); + + add_edge(0, 1); + add_edge(0, 2); + add_edge(0, 3); + add_edge(0, 4); + + const auto center = graph::center(adj); + const auto diameter = graph::diameter(adj); + + EXPECT_EQ(center, expectedCenter); + EXPECT_EQ(diameter, expectedDiameter); +} + +TEST_F(GraphFixture, DoubleStarTreeTest) +{ + const std::vector expectedCenter {0, 1}; + const int expectedDiameter {3}; + + initialize(8); + + add_edge(0, 2); + add_edge(0, 3); + add_edge(0, 4); + add_edge(0, 1); + add_edge(1, 5); + add_edge(1, 6); + add_edge(1, 7); + + auto center = graph::center(adj); + const auto diameter = graph::diameter(adj); + + std::sort(center.begin(), center.end()); + + EXPECT_EQ(center, expectedCenter); + EXPECT_EQ(diameter, expectedDiameter); +} + +TEST_F(GraphFixture, EvenTreePathTest) +{ + const std::vector expectedCenter {3}; + const int expectedDiameter {6}; + + initialize(7); + + add_edge(0, 1); + add_edge(1, 2); + add_edge(2, 3); + add_edge(3, 4); + add_edge(4, 5); + add_edge(5, 6); + + const auto center = graph::center(adj); + const auto diameter = graph::diameter(adj); + + EXPECT_EQ(center, expectedCenter); + EXPECT_EQ(diameter, expectedDiameter); +} + +TEST_F(GraphFixture, OddTreePathTest) +{ + const std::vector expectedCenter {2, 3}; + const int expectedDiameter {5}; + + initialize(6); + + add_edge(0, 1); + add_edge(1, 2); + add_edge(2, 3); + add_edge(3, 4); + add_edge(4, 5); + + auto center = graph::center(adj); + const auto diameter = graph::diameter(adj); + + std::sort(center.begin(), center.end()); + + EXPECT_EQ(center, expectedCenter); + EXPECT_EQ(diameter, expectedDiameter); +} \ No newline at end of file diff --git a/competitive_programming/test/math/CMakeLists.txt b/competitive_programming/test/math/CMakeLists.txt index bbc92b8..055686a 100644 --- a/competitive_programming/test/math/CMakeLists.txt +++ b/competitive_programming/test/math/CMakeLists.txt @@ -18,9 +18,15 @@ add_executable(mint mint.cpp) target_include_directories(mint PRIVATE ${PROJECT_INCLUDE_DIR}) target_link_libraries(mint PRIVATE GTest::gtest GTest::gtest_main) +# Pollard Rho +add_executable(pollard-rho pollard_rho.cpp) +target_include_directories(pollard-rho PRIVATE ${PROJECT_INCLUDE_DIR}) +target_link_libraries(pollard-rho PRIVATE GTest::gtest GTest::gtest_main) + include(GoogleTest) gtest_discover_tests(bin-exp) gtest_discover_tests(miller-rabin) gtest_discover_tests(euclides-ext) -gtest_discover_tests(mint) \ No newline at end of file +gtest_discover_tests(mint) +gtest_discover_tests(pollard-rho) \ No newline at end of file diff --git a/competitive_programming/test/math/mint.cpp b/competitive_programming/test/math/mint.cpp index 4100746..6d228ca 100644 --- a/competitive_programming/test/math/mint.cpp +++ b/competitive_programming/test/math/mint.cpp @@ -168,3 +168,14 @@ TEST(Mint, NegativeTest) EXPECT_EQ(result, expected); } + +TEST(Mint, InverseTest) +{ + constexpr int MOD = 1e9 + 9; + const mint num = 2; + const mint expected = 1; + + const auto inverse = num.inv(); + + EXPECT_EQ(inverse * num, expected); +} diff --git a/competitive_programming/test/math/pollard_rho.cpp b/competitive_programming/test/math/pollard_rho.cpp new file mode 100644 index 0000000..1c3f076 --- /dev/null +++ b/competitive_programming/test/math/pollard_rho.cpp @@ -0,0 +1,37 @@ +#include + +#include "math/pollard_rho.hpp" + +using namespace math::factorization; + +TEST(PollardRho, FactorizationTest) +{ + constexpr long long n = 4128133LL * 33013LL * 17LL * 17LL; + const std::vector> expected = { + {17LL, 2}, + {33013LL, 1}, + {4128133LL, 1} + }; + + auto factors = factorize(n); + + std::sort(factors.begin(), factors.end()); + + EXPECT_EQ(factors, expected); +} + +TEST(PollardRho, LargeFactorizationTest) +{ + constexpr __int128 n = (__int128)2879704699LL * (__int128)57551099LL; + + const std::vector> expected = { + {(__int128)57551099, 1}, + {(__int128)2879704699LL, 1} + }; + + auto factors = factorize(n); + + std::sort(factors.begin(), factors.end()); + + EXPECT_EQ(factors, expected); +} \ No newline at end of file diff --git a/competitive_programming/test/string/CMakeLists.txt b/competitive_programming/test/string/CMakeLists.txt index 598ef12..28b3292 100644 --- a/competitive_programming/test/string/CMakeLists.txt +++ b/competitive_programming/test/string/CMakeLists.txt @@ -1,9 +1,14 @@ +# Z function add_executable(z-function z_function.cpp) - target_include_directories(z-function PRIVATE ${PROJECT_INCLUDE_DIR}) - target_link_libraries(z-function PRIVATE GTest::gtest GTest::gtest_main) +# KMP +add_executable(kmp kmp.cpp) +target_include_directories(kmp PRIVATE ${PROJECT_INCLUDE_DIR}) +target_link_libraries(kmp PRIVATE GTest::gtest GTest::gtest_main) + include(GoogleTest) -gtest_discover_tests(z-function) \ No newline at end of file +gtest_discover_tests(z-function) +gtest_discover_tests(kmp) diff --git a/competitive_programming/test/string/kmp.cpp b/competitive_programming/test/string/kmp.cpp new file mode 100644 index 0000000..0a456f4 --- /dev/null +++ b/competitive_programming/test/string/kmp.cpp @@ -0,0 +1,53 @@ +#include + +#include "string/kmp.hpp" + +TEST(KMP, Palindrome) +{ + const std::string word = "abcbcba"; + const std::vector expected {0, 0, 0, 0, 0, 0, 1}; + + const auto kmp = strings::kmp(word); + + EXPECT_EQ(kmp, expected); +} + +TEST(KMP, Repeated) +{ + const std::string word = "abcabcabc"; + const std::vector expected {0, 0, 0, 1, 2, 3, 4, 5, 6}; + + const auto kmp = strings::kmp(word); + + EXPECT_EQ(kmp, expected); +} + +TEST(KMP, NoPrefix) +{ + const std::string word = "abcdef"; + const std::vector expected {0, 0, 0, 0, 0, 0}; + + const auto kmp = strings::kmp(word); + + EXPECT_EQ(kmp, expected); +} + +TEST(KMP, AllSame) +{ + const std::string word = "aaaaaa"; + const std::vector expected {0, 1, 2, 3, 4, 5}; + + const auto kmp = strings::kmp(word); + + EXPECT_EQ(kmp, expected); +} + +TEST(KMP, Empty) +{ + const std::string word = ""; + const std::vector expected {}; + + const auto kmp = strings::kmp(word); + + EXPECT_EQ(kmp, expected); +}