Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
string_palindromes_test.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
37# include <gtest/gtest.h>
38
39# include <String_Palindromes.H>
40
41using namespace Aleph;
42
44{
45 const auto r = manacher("abacaba");
46 EXPECT_EQ(r.longest_palindrome, "abacaba");
47 EXPECT_EQ(r.longest_begin, 0u);
48 EXPECT_EQ(r.longest_length, 7u);
49 ASSERT_EQ(r.odd_radius.size(), 7u);
50 EXPECT_EQ(r.odd_radius[3], 4u);
51}
52
54{
55 const auto r = manacher("abba");
56 EXPECT_EQ(r.longest_palindrome, "abba");
57 EXPECT_EQ(r.longest_begin, 0u);
58 EXPECT_EQ(r.longest_length, 4u);
59 ASSERT_EQ(r.even_radius.size(), 4u);
60 EXPECT_GE(r.even_radius[2], 2u);
61}
62
64{
65 const auto r = manacher("aaaa");
66 EXPECT_EQ(r.longest_palindrome, "aaaa");
68}
69
71{
72 const auto r = manacher("");
73 EXPECT_TRUE(r.odd_radius.is_empty());
74 EXPECT_TRUE(r.even_radius.is_empty());
75 EXPECT_EQ(r.longest_length, 0u);
76 EXPECT_EQ(r.longest_palindrome, "");
77}
78
80{
81 const auto r = manacher("x");
82 EXPECT_EQ(r.longest_palindrome, "x");
83 EXPECT_EQ(r.longest_length, 1u);
84 EXPECT_EQ(r.longest_begin, 0u);
85}
86
88{
89 // "abcdef" — no palindrome longer than 1 character
90 const auto r = manacher("abcdef");
91 EXPECT_EQ(r.longest_length, 1u);
92}
93
95{
96 // Build a long palindrome: "abcba" repeated structure
97 std::string half = "abcdefghijklmnopqrstuvwxyz";
98 std::string palindrome = half;
99 std::string rev_half(half.rbegin(), half.rend());
101
102 const auto r = manacher(palindrome);
103 EXPECT_EQ(r.longest_length, palindrome.size());
104 EXPECT_EQ(r.longest_palindrome, palindrome);
105}
106
108{
109 const auto r = manacher("xxxracecarxxx");
110 EXPECT_EQ(r.longest_palindrome, "xxxracecarxxx");
111 EXPECT_EQ(r.longest_length, 13u);
112}
113
115{
116 // 1000 chars all same letter — entire string is a palindrome
117 const std::string text(1000, 'z');
118 const auto r = manacher(text);
119 EXPECT_EQ(r.longest_length, 1000u);
120 EXPECT_EQ(r.longest_palindrome, text);
121}
122
123// --- 3.4 Manacher: verify radius arrays directly ---
124
126{
127 // "abacaba"
128 // Char: a b a c a b a
129 // odd_radius: 1 2 1 4 1 2 1
130 // index 1: "aba" centered at 'b' -> radius 2
131 // index 3: "abacaba" centered at 'c' -> radius 4
132 // index 5: "aba" centered at 'b' -> radius 2
133 const auto r = manacher("abacaba");
134 ASSERT_EQ(r.odd_radius.size(), 7u);
135 EXPECT_EQ(r.odd_radius[0], 1u);
136 EXPECT_EQ(r.odd_radius[1], 2u);
137 EXPECT_EQ(r.odd_radius[2], 1u);
138 EXPECT_EQ(r.odd_radius[3], 4u);
139 EXPECT_EQ(r.odd_radius[4], 1u);
140 EXPECT_EQ(r.odd_radius[5], 2u);
141 EXPECT_EQ(r.odd_radius[6], 1u);
142}
143
145{
146 // "abba"
147 // even_radius[i] = max k such that text[i-k..i-1] == rev(text[i..i+k-1])
148 // i=0: 0, i=1: 0, i=2: 2 ("abba"), i=3: 0
149 const auto r = manacher("abba");
150 ASSERT_EQ(r.even_radius.size(), 4u);
151 EXPECT_EQ(r.even_radius[0], 0u);
152 EXPECT_EQ(r.even_radius[1], 0u);
153 EXPECT_EQ(r.even_radius[2], 2u);
154 EXPECT_EQ(r.even_radius[3], 0u);
155}
156
158{
159 // "aaaa"
160 // i=0: radius 1, i=1: radius 2, i=2: radius 2, i=3: radius 1
161 const auto r = manacher("aaaa");
162 ASSERT_EQ(r.odd_radius.size(), 4u);
163 EXPECT_EQ(r.odd_radius[0], 1u);
164 EXPECT_EQ(r.odd_radius[1], 2u);
165 EXPECT_EQ(r.odd_radius[2], 2u);
166 EXPECT_EQ(r.odd_radius[3], 1u);
167}
168
170{
171 // "aaaa" even radii
172 // i=0: 0, i=1: 1, i=2: 2, i=3: 1
173 const auto r = manacher("aaaa");
174 ASSERT_EQ(r.even_radius.size(), 4u);
175 EXPECT_EQ(r.even_radius[0], 0u);
176 EXPECT_EQ(r.even_radius[1], 1u);
177 EXPECT_EQ(r.even_radius[2], 2u);
178 EXPECT_EQ(r.even_radius[3], 1u);
179}
180
182{
183 // Verify Manacher's radius arrays against brute-force for a test string
184 const std::string text = "abcbaXcbcYaabaa";
185 const size_t n = text.size();
186 const auto r = manacher(text);
187
188 ASSERT_EQ(r.odd_radius.size(), n);
189 ASSERT_EQ(r.even_radius.size(), n);
190
191 // Brute-force verify odd radii
192 for (size_t i = 0; i < n; ++i)
193 {
194 size_t k = 1;
195 while (i >= k and i + k < n and text[i - k] == text[i + k])
196 ++k;
197 EXPECT_EQ(r.odd_radius[i], k) << "odd_radius mismatch at i=" << i;
198 }
199
200 // Brute-force verify even radii
201 for (size_t i = 0; i < n; ++i)
202 {
203 size_t k = 0;
204 while (i >= k + 1 and i + k < n and text[i - k - 1] == text[i + k])
205 ++k;
206 EXPECT_EQ(r.even_radius[i], k) << "even_radius mismatch at i=" << i;
207 }
208}
209
211{
212 const auto r = manacher("x");
213 ASSERT_EQ(r.odd_radius.size(), 1u);
214 ASSERT_EQ(r.even_radius.size(), 1u);
215 EXPECT_EQ(r.odd_radius[0], 1u);
216 EXPECT_EQ(r.even_radius[0], 0u);
217}
218
220{
221 {
222 const auto r = manacher("ab");
223 ASSERT_EQ(r.odd_radius.size(), 2u);
224 EXPECT_EQ(r.odd_radius[0], 1u);
225 EXPECT_EQ(r.odd_radius[1], 1u);
226 EXPECT_EQ(r.even_radius[0], 0u);
227 EXPECT_EQ(r.even_radius[1], 0u);
228 }
229 {
230 const auto r = manacher("aa");
231 ASSERT_EQ(r.odd_radius.size(), 2u);
232 EXPECT_EQ(r.odd_radius[0], 1u);
233 EXPECT_EQ(r.odd_radius[1], 1u);
234 EXPECT_EQ(r.even_radius[0], 0u);
235 EXPECT_EQ(r.even_radius[1], 1u);
236 }
237}
238
240{
241 // Build a 2000-character string and verify radii match brute force
242 std::string text;
243 text.reserve(2000);
244 for (int i = 0; i < 2000; ++i)
245 text.push_back('a' + (i * 7 + 3) % 4); // small alphabet
246
247 const size_t n = text.size();
248 const auto r = manacher(text);
249
250 ASSERT_EQ(r.odd_radius.size(), n);
251 ASSERT_EQ(r.even_radius.size(), n);
252
253 for (size_t i = 0; i < n; ++i)
254 {
255 size_t k = 1;
256 while (i >= k and i + k < n and text[i - k] == text[i + k])
257 ++k;
258 EXPECT_EQ(r.odd_radius[i], k);
259 }
260
261 for (size_t i = 0; i < n; ++i)
262 {
263 size_t k = 0;
264 while (i >= k + 1 and i + k < n and text[i - k - 1] == text[i + k])
265 ++k;
266 EXPECT_EQ(r.even_radius[i], k);
267 }
268}
Palindrome algorithms over strings.
#define TEST(name)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::string longest_palindromic_substring(const std::string_view text)
Convenience wrapper returning only the longest palindromic substring.
Manacher_Result manacher(const std::string_view text)
Compute palindromic radii and the longest palindrome with Manacher.
static int * k
gsl_rng * r