Checking if a String is a Palindrome
How can I efficiently check if a std::string is a palindrome?
A palindrome is a word, phrase, number, or other sequence of characters that reads the same forward and backward. Checking if a string is a palindrome is a common programming task. Here's an efficient way to do this in C++ using std::string:
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
#include <vector>
bool is_palindrome(const std::string& str) {
if (str.empty()) {
return true;
}
auto left = str.begin();
auto right = str.end() - 1;
while (left < right) {
// Skip non-alphanumeric characters
while (left < right && !std::isalnum(*left))
++left;
while (left < right && !std::isalnum(*right))
--right;
if (std::tolower(*left) != std::tolower(*right)) {
return false;
}
++left;
--right;
}
return true;
}
int main() {
std::vector<std::string> tests{
"A man, a plan, a canal: Panama", "race a car",
"Was it a car or a cat I saw?", "Hello, World!",
"" // empty string
};
for (const auto& test : tests) {
std::cout << "\"" << test << "\" is " << (
is_palindrome(test) ?
"a palindrome" : "not a palindrome"
) << '\n';
}
}"A man, a plan, a canal: Panama" is a palindrome
"race a car" is not a palindrome
"Was it a car or a cat I saw?" is a palindrome
"Hello, World!" is not a palindrome
"" is a palindromeLet's break down the is_palindrome() function:
- We use two iterators,
leftandright, starting from the beginning and end of the string respectively. - We skip non-alphanumeric characters using
std::isalnum(). - We compare characters case-insensitively using
std::tolower(). - If we find a mismatch, we return
false. - If we make it through the entire string without finding a mismatch, we return
true.
This approach is efficient because:
- It works in-place, without creating any new strings.
- It stops as soon as it finds a mismatch.
- It only traverses half the string in the worst case.
For a simpler implementation that considers all characters and is case-sensitive, you could use std::equal():
bool simple_palindrome(const std::string& str) {
return std::equal(
str.begin(),
str.begin() + str.length() / 2,
str.rbegin()
);
}This method is shorter but less flexible, as it doesn't ignore non-alphanumeric characters or handle case-insensitivity.
For very long strings, you might consider using std::string_view (C++17) to avoid copying:
#include <string_view>
bool is_palindrome(std::string_view sv) {
// Similar implementation as before,
// but using string_view
}Remember, the most appropriate method depends on your specific requirements, such as whether you need to ignore punctuation and whitespace, whether the check should be case-sensitive, and what constitutes a valid character in your palindrome definition.
A Deeper Look at the std::string Class
A detailed guide to std::string, covering the most essential methods and operators