我代表一位朋友发帖,因为我觉得这很有趣:
取字符串“abb”。通过遗漏 任何数量的字母少于 字符串的长度我们最终得到7 字符串。
a b b ab ab bb abb
这4个是回文。
类似于字符串
“hihellolookhavealookatthispalindromexxqwertyuiopasdfghjklzxcvbnmmnbvcxzlkjhgfdsapoiuytrewqxxsoundsfamiliardoesit”
(长度为112弦)2 ^ 112 - 1 可以形成字符串。
其中有多少是 回文??
下面是他的实现(在C ++中,C也很好)。用很长的词来说它很慢;他想知道什么是最快的算法(我也很好奇:D)。
#include <iostream>
#include <cstring>
using namespace std;
void find_palindrome(const char* str, const char* max, long& count)
{
for(const char* begin = str; begin < max; begin++) {
count++;
const char* end = strchr(begin + 1, *begin);
while(end != NULL) {
count++;
find_palindrome(begin + 1, end, count);
end = strchr(end + 1, *begin);
}
}
}
int main(int argc, char *argv[])
{
const char* s = "hihellolookhavealookatthis";
long count = 0;
find_palindrome(s, strlen(s) + s, count);
cout << count << endl;
}
答案 0 :(得分:15)
首先,您的朋友的解决方案似乎有一个错误,因为strchr
可以搜索过max
。即使你解决了这个问题,解决方案也是指数级的。
要获得更快的解决方案,您可以使用dynamic programming在O(n ^ 3)时间内解决此问题。这将需要O(n ^ 2)额外的内存。请注意,对于长字符串,即使是我在这里使用的64位整数也不足以容纳解决方案。
#define MAX_SIZE 1000
long long numFound[MAX_SIZE][MAX_SIZE]; //intermediate results, indexed by [startPosition][endPosition]
long long countPalindromes(const char *str) {
int len = strlen(str);
for (int startPos=0; startPos<=len; startPos++)
for (int endPos=0; endPos<=len; endPos++)
numFound[startPos][endPos] = 0;
for (int spanSize=1; spanSize<=len; spanSize++) {
for (int startPos=0; startPos<=len-spanSize; startPos++) {
int endPos = startPos + spanSize;
long long count = numFound[startPos+1][endPos]; //if str[startPos] is not in the palindrome, this will be the count
char ch = str[startPos];
//if str[startPos] is in the palindrome, choose a matching character for the palindrome end
for (int searchPos=startPos; searchPos<endPos; searchPos++) {
if (str[searchPos] == ch)
count += 1 + numFound[startPos+1][searchPos];
}
numFound[startPos][endPos] = count;
}
}
return numFound[0][len];
}
说明:
数组numFound[startPos][endPos]
将包含索引startPos到endPos的子字符串中包含的回文数。
我们遍历所有索引对(startPos,endPos),从短跨度开始并移动到更长的索引。对于每个这样的对,有两个选项:
str[startPos]
处的角色不在回文区。在这种情况下,有numFound[startPos+1][endPos]
个可能的回文 - 我们已经计算过的数字。
str[startPos]
处的字符位于回文结构(开头)。我们扫描字符串以找到匹配的字符放在回文末尾。对于每个这样的字符,我们使用numFound
中已经计算的结果来查找内部回文的可能性数量。
修改强>:
澄清:当我说“字符串中包含的回文数量”时,这包括非连续的子串。例如,回文“aba”包含在“abca”中。
通过利用numFound[startPos][x]
的计算仅需要知道所有y的numFound[startPos+1][y]
,可以将内存使用量减少到O(n)。我不会在这里这样做,因为它会使代码复杂化。
预生成包含每个字母的索引列表可以使内循环更快,但总体上仍然是O(n ^ 3)。
答案 1 :(得分:6)
我有办法可以在O(N ^ 2)时间和O(1)空间中进行,但我认为必须有其他更好的方法。
基本思想是长回文必须包含小回文,所以我们只搜索最小匹配,这意味着两种情况:“aa”,“aba”。如果我们找到了,那么扩展以查看它是否是长回文的一部分。
int count_palindromic_slices(const string &S) {
int count = 0;
for (int position=0; position<S.length(); position++) {
int offset = 0;
// Check the "aa" situation
while((position-offset>=0) && (position+offset+1)<S.length() && (S.at(position-offset))==(S.at(position+offset+1))) {
count ++;
offset ++;
}
offset = 1; // reset it for the odd length checking
// Check the string for "aba" situation
while((position-offset>=0) && position+offset<S.length() && (S.at(position-offset))==(S.at(position+offset))) {
count ++;
offset ++;
}
}
return count;
}
2012年6月14日 经过一番调查,我相信这是最好的方法。 比接受的答案更快。
答案 2 :(得分:2)
在进行初始遍历并建立每个角色的所有出现的索引时,是否有任何里程。
h = { 0, 2, 27}
i = { 1, 30 }
etc.
现在从左边开始,h,只有可能的palidromes在3和17,char [0 + 1] == char [3 -1]等等得了回文。 char [0 + 1] == char [27 -1]否,不需要进一步分析char [0]。
转到char [1],只需要示例char [30 -1]和内部。
然后可能会变得聪明,当你确定从位置x-> y运行的回文时,所有内部子集都是已知的回文,因此我们已经处理了一些项目,可以从后期检查中消除这些情况。 / p>
答案 3 :(得分:2)
我的解决方案使用O(n)
内存和O(n^2)
时间,其中n
是字符串长度:
<强> palindrome.c:强>
#include <stdio.h>
#include <string.h>
typedef unsigned long long ull;
ull countPalindromesHelper (const char* str, const size_t len, const size_t begin, const size_t end, const ull count) {
if (begin <= 0 || end >= len) {
return count;
}
const char pred = str [begin - 1];
const char succ = str [end];
if (pred == succ) {
const ull newCount = count == 0 ? 1 : count * 2;
return countPalindromesHelper (str, len, begin - 1, end + 1, newCount);
}
return count;
}
ull countPalindromes (const char* str) {
ull count = 0;
size_t len = strlen (str);
size_t i;
for (i = 0; i < len; ++i) {
count += countPalindromesHelper (str, len, i, i, 0); // even length palindromes
count += countPalindromesHelper (str, len, i, i + 1, 1); // odd length palindromes
}
return count;
}
int main (int argc, char* argv[]) {
if (argc < 2) {
return 0;
}
const char* str = argv [1];
ull count = countPalindromes (str);
printf ("%llu\n", count);
return 0;
}
<强>用法:强>
$ gcc palindrome.c -o palindrome
$ ./palindrome myteststring
编辑:我误解了问题是问题的连续子字符串版本。现在假设有人想找到非连续版本的回文数,我强烈怀疑,只要使用不同的字符数及其各自的字符数,就可以使用数学方程来解决它。
答案 4 :(得分:1)
每个角色都是自己的回文(减去重复的字符)
每一对相同的人物。
每对相同的角色,所有的回文都夹在中间,可以用重复之间的字符串制成。
递归申请。
这似乎就是你正在做的事情,虽然我不确定你是否不会重复计算重复字符的边缘情况。
所以,基本上,我想不出更好的方法。
编辑:
思考更多,
它可以通过缓存来改进,因为您有时会在同一个子字符串中多次计算回文。所以,我想这表明肯定有更好的方法。
答案 5 :(得分:1)
这是用Java和C ++编写的字符串中的program for finding all the possible palindromes。
答案 6 :(得分:0)
int main()
{
string palindrome;
cout << "Enter a String to check if it is a Palindrome";
cin >> palindrome;
int length = palindrome.length();
cout << "the length of the string is " << length << endl;
int end = length - 1;
int start = 0;
int check=1;
while (end >= start) {
if (palindrome[start] != palindrome[end]) {
cout << "The string is not a palindrome";
check=0;
break;
}
else
{
start++;
end--;
}
}
if(check)
cout << "The string is a Palindrome" << endl;
}
答案 7 :(得分:0)
public String[] findPalindromes(String source) {
Set<String> palindromes = new HashSet<String>();
int count = 0;
for(int i=0; i<source.length()-1; i++) {
for(int j= i+1; j<source.length(); j++) {
String palindromeCandidate = new String(source.substring(i, j+1));
if(isPalindrome(palindromeCandidate)) {
palindromes.add(palindromeCandidate);
}
}
}
return palindromes.toArray(new String[palindromes.size()]);
}
private boolean isPalindrome(String source) {
int i =0;
int k = source.length()-1;
for(i=0; i<source.length()/2; i++) {
if(source.charAt(i) != source.charAt(k)) {
return false;
}
k--;
}
return true;
}
答案 8 :(得分:-2)
我不确定,但你可能会尝试使用傅立叶。这个问题提醒我:O(nlogn) Algorithm - Find three evenly spaced ones within binary string
只是我的2cents