递归主要包含三个主要部分:
- 一个停止条件(当您达到一个足够小的数组大小以保证回文(
0 或1)时),
- 一个计算步骤(例如,比较数组的第一项和最后一项并确定继续是否有意义)和
- 嵌套递归调用的数据子集选择(例如,大小为
n - 2 的数组,不包括第一个和最后一个字符,我们已经比较并发现“值得回文”)。
代码中的三个组件:
bool isPalindrome(int arr[], size_t n) {
return n < 2 || (
arr[0] == arr[n - 1] &&
isPalindrome(arr + 1, n - 2));
}
当然你可能想稍微测试一下这个函数(别忘了在valgrind下运行它):
#include <iostream>
int main() {
std::cout << isPalindrome((int[0]){}, 0) << std::endl;
std::cout << isPalindrome((int[1]){1}, 1) << std::endl;
std::cout << isPalindrome((int[2]){1, 1}, 2) << std::endl;
std::cout << isPalindrome((int[2]){2, 1}, 2) << std::endl;
std::cout << isPalindrome((int[2]){1, 2}, 2) << std::endl;
std::cout << isPalindrome((int[3]){1, 2, 1}, 3) << std::endl;
std::cout << isPalindrome((int[3]){2, 2, 2}, 3) << std::endl;
std::cout << isPalindrome((int[3]){2, 2, 1}, 3) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 1, 2}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 2, 1}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 2, 3, 2}, 4) << std::endl;
std::cout << isPalindrome((int[4]){2, 3, 2, 1}, 4) << std::endl;
std::cout << isPalindrome((int[4]){1, 3, 3, 1}, 4) << std::endl;
}
作为旁注,这个^^^ 与数组的致命斗争表明不同的数据类型将是一个更好的选择。例如,std::string 或std::vector 可以更容易地进行初始化方式,应该通过引用传递,并且作为奖励,STL 容器会携带大小信息。此外,您可以在递归中将std::string_view 用于子字符串,将std::span 用于“子向量”,而无需在每个递归级别上一遍又一遍地复制容器。
这是一个带有std::string_view 的示例和三个不同的实现(一个有递归,两个没有递归):
#include <iostream>
#include <string_view>
bool isPalindrome1(const std::string_view s) {
return s.size() < 2 || (
s[0] == s[s.size() - 1] &&
isPalindrome1(s.substr(1, s.size() - 2)));
}
bool isPalindrome2(const std::string_view s) {
const size_t end = s.size() / 2;
for (size_t i = 0; i < end; ++i)
if (s[i] != s[s.size() - i - 1])
return false;
return true;
}
bool isPalindrome3(const std::string_view s) {
auto b = s.begin();
const auto end = b + s.size() / 2;
auto e = s.rbegin();
for (; b < end; ++b, ++e)
if (*b != *e) return false;
return true;
}
int main() {
for (auto isPalindrome : {isPalindrome1,
isPalindrome2,
isPalindrome3}) {
std::cout << isPalindrome("") << std::endl;
std::cout << isPalindrome("a") << std::endl;
std::cout << isPalindrome("ab") << std::endl;
std::cout << isPalindrome("aa") << std::endl;
std::cout << isPalindrome("abc") << std::endl;
std::cout << isPalindrome("aba") << std::endl;
std::cout << isPalindrome("baab") << std::endl;
std::cout << isPalindrome("baba") << std::endl;
}
}