返回字符串的散点回文计数
return count of scatter palindrome of a string
我们必须在给定字符串内找到分散回文字符串,并返回字符串中散点回文的编号。例如,给定字符串"aabb",散点回文是a,aa,aab,aabb,a,abb,b,bb和b。这里有 9 个子字符串是分散回文。
我想到了蛮力方法,即生成所有子字符串并检查它们,但我想找到更好的方法。
首先,让我们考虑如何找到字符串是否可以是散点回文。
让我们考虑一下我们的字符串仅由小写字符组成的情况。
在以下情况下,字符串可以被视为分散回文:
- 当字符串长度为偶数时:字符串中出现的所有字符必须出现偶数次。
- 当字符串长度为奇数时:字符串中只有一个字符出现奇数次,其他字符出现偶数次。
因此,要检查字符串是否可以是散点回文,我们只需要检查字符串中每个字符的出现次数。这可以在 O(n) 中完成,其中 n 是字符串的长度。
对于您的解决方案: 生成所有子字符串的时间复杂度为 O(n2)。为了检查子串是否是散射回文,我们需要另一个 O(n)。因此,总时间复杂度为 O(n3)。
我们可以在检查时降低 O(n) 因子,这可以将总时间复杂度降低到 O(n2)。
为此,您可以采用大小为 n*26 的二维数组,其中 n 是字符串的长度。设该数组为 A[n][26]。因此,A[i][j] 存储从0 到 i 的第 j 个字符* 的出现总数。
所以对于字符串"abca",你的数组看起来像
1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 02 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0现在,对于从索引 l 到 r 的任何子字符串,A[r]-A[l-1] 为您提供子字符串中每个字符的出现次数。要检查这是否可以是散射回文,我们需要 26 个操作。 因此,解的时间复杂度变为 O(n 2* 26),其渐近性与 O(n2) 相同。
这里我们使用 n*26 的额外空间。这可以通过更好的方法避免。
我们将每个字符的出现日期存储在数组中,而不是将其存储为整数。如果第 i 个位是 lsb 中的"1",例如第 j 个索引,则表示第i 个字符从 0 到 j个索引出现了奇数次。如果为"0",则表示第 i 个字符* 已出现偶数次。
考虑此示例,其中输入字符串为"abca">
所以我们的辅助阵列将是
1 3 7 6
1 -> (0001) ["a"发生过一次]
3 -> (0011) ["a"和"b"出现过一次]
7 -> (0111) ["a"、"b"和"c"各出现一次]
6 -> (0110) ["a"发生两次,而"b"和"c"发生一次]
所以现在对于从索引 l 到 r 的任何子字符串 A[r] xor A[l-1] 给出整数,如果它是 0 或 2 的幂,它将包含在最终答案中。(它有所有 0 位或只有一个"1"位)
伪代码给出如下:
input string = s
ans = 0
n = s.length
for i=1:n
A[i]=A[i-1]^(1<<(s[i-1]-97))
for i=1:n
for j=i;n
x=A[j]^A[i-1]
if (x&(x-1)) == 0 //if x is a power of 2 or not
ans++;
endif
endfor
endfor
散射回文的总数存储在ans中。
此方法的空间复杂度为 O(n)。此外,它的运行时间将比前面解释的方法更好。
- 这里的第 i个字符是指认为"a"是第 0 个字符,"b"是第一个字符的字符,依此类推。
类似的任务是在NEERC 2012-2013(问题H. Hyperdrome,在这里声明)。解释解决方案的幻灯片在这里。如有必要,我可以更详细地解释(我在比赛中解决了它)。
小写字母字符串的解决方案:
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
long long answer = 0;
string s;
cin >> s;
map<int, int> m;
m[0] = 1;
int x = 0;
for (auto& c : s) {
int d = c - '0';
x ^= 1 << d;
answer += m[x];
for (int i = 0; i < 26; ++i) {
answer += m[x ^ (1 << i)];
}
m[x] += 1;
}
cout << answer << endl;
return 0;
}
复杂度是O(|A| * n * log(n))
其中|A|
是字母大小(|A| = 26
),n
是字符串s
的长度。log(n)
是访问map
的难度(可以用具有复杂性O(1)
的哈希代替)。
任何单个字符都是散文回文。任何一对相同的字符都是散射回文。如果 P 是散射回文,则 C + P + C 也是散点回文,其中 C 是字符,+ 是字符串连接运算符。这导致了以下算法,我们从给定字符串中选取字符来递归构建所有可能的回文。下面是伪代码。注意|S|
是S
中的字符数。
设S
是给定字符串中的字符集。调用countScatterPalindrome()
count
后将是S
中的散射回文数。
count = 0; // The number of scatter palindome in S.
countScatterPalindrome(S)
{
if |S| == 1 then
count++;
return true;
if |S| == 0
return true;
remove 2 characters that are equal from S
if countScatterPalindrome(S) == true
count++
return true;
return false;
}
- 将 S1 转换为回文,并将 S2 作为其子字符串
- 程序以查找给定字符串中回文的子字符串的数量
- 如何创建一个程序来标识最长的子字符串回文,而不考虑字母大小写
- 返回字符串的散点回文计数
- C++ 递归布尔回文(字符串 s)
- 寻找一种更有效的方法来使用 STL 函数检查字符串是否为回文
- 回文字符串问题:为什么我必须放+1而不是-1才能让这个代码工作
- 尝试使用C++实现检测字符串中回文的递归版本.在这里遇到了一些麻烦
- 找到字符串中的所有回文
- 验证字符串是否为回文的函数
- 字符串回文程序不会忽略案例
- 字符串中的最小回文计数
- 为给定字符串生成所有可能的回文
- 仅删除一个元素以制作字符串回文
- 使用数组和无指针创建回文字符串检查器C++
- 检查字符串是否为回文
- 回文子字符串程序无法运行
- 不能在回文程序中输入多个字符串
- 回文程序和 C 样式字符串中不需要的字符
- 带有堆栈和队列的字符串回文(c++)