先决条件: Z算法
给定字符串S ,任务是查找在执行给定步骤后可以形成的最大回文数:
- 选择长度相等的非空前缀P和非空子串T。
- 反转P或T并将其串联。
注意: P和T可以重叠。
例子:
Input: S = “abab”
Output: 6
Explanation:
Consider prefix as S[0 : 1] ( = “ab“) and reverse the substring S[2 : 3]. Resultant string after concatenating prefix with reversed substring is “abba”, which is a palindrome.
All possible prefixes are [“a”, “ab”, ”aba”, ”abab”].
All possible suffixes are [“a”, ”b”, ”a”, ”b”, ”ab”, ”ba”, ”ab”, ”aba”, ”bab”, ”abab”].
Therefore, all possible palindromes are [“aa”, ”aa”, ”abba”, ”abba”, ”abaaba”, ”ababbaba”].
Input: S = “abcd”
Output: 4
天真的方法:生成所有可能的前缀和所有可能的子字符串。连接所有等长的前缀和子字符串(反转后)对,并检查获得的字符串是否是回文。
时间复杂度: O(N 3 )
辅助空间: O(N 2 )
高效的方法:可以基于以下观察条件来优化上述方法:连接字符串的长度将始终是均匀的。因此,仅需考虑那些字符串,其中前半部分是后半部分的镜像。因此,问题减少到对等于该前缀的每个可能前缀的子字符串进行计数,这可以使用Z函数来完成。
The z-function over a string will return an array Z[] where Z[i] represents the length of the longest prefix that same as the sub-string starting at position i and ending at position i+Z[i]. Hence the count will be .
请按照以下步骤解决问题:
- 这个想法是要维持一个间隔[l,r] ,该间隔是最大r的间隔,这样[l,r]是一个前缀子串(也是子串的前缀)。
- 如果i≤r ,则Z [i]等于r – i + 1和Z [i – 1]的最小值。
- 现在,增量Z [I],直到我+ Z [i]是小于N和字符在指数Z [i]和I + Z [I]是给定字符串中相等。
- 现在,如果i + Z [i] – 1> r ,则将l设置为i并将r设置为i + Z [i] – 1 。
- 对0到N-1的i重复上述步骤。
- 答案是每个i (0≤i≤N-1)的Z [i] +1之和。
下面是上述方法的实现:
C++14
// C++ program the above approach
#include
using namespace std;
// Function to calculate the
// number of palindromes
int countPalindromes(string S)
{
int N = (int)S.length();
vector Z(N);
// Calculation of Z-array
int l = 0, r = 0;
for (int i = 1; i < N; i++) {
if (i <= r)
Z[i] = min(r - i + 1, Z[i - l]);
while (i + Z[i] < N
&& S[Z[i]] == S[i + Z[i]]) {
Z[i]++;
}
if (i + Z[i] - 1 > r) {
l = i;
r = i + Z[i] - 1;
}
}
// Calculation of sigma(Z[i]+1)
int sum = 0;
for (int i = 0; i < Z.size(); i++) {
sum += Z[i] + 1;
}
// Return the count
return sum;
}
// Driver Code
int main()
{
// Given String
string S = "abab";
cout << countPalindromes(S);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG{
// Function to calculate the
// number of palindromes
static int countPalindromes(String S)
{
int N = (int)S.length();
int[] Z = new int[(N)];
// Calculation of Z-array
int l = 0, r = 0;
for(int i = 1; i < N; i++)
{
if (i <= r)
Z[i] = Math.min(r - i + 1,
Z[i - l]);
while (i + Z[i] < N &&
S.charAt(Z[i]) ==
S.charAt(i + Z[i]))
{
Z[i]++;
}
if (i + Z[i] - 1 > r)
{
l = i;
r = i + Z[i] - 1;
}
}
// Calculation of sigma(Z[i]+1)
int sum = 0;
for(int i = 0; i < Z.length; i++)
{
sum += Z[i] + 1;
}
// Return the count
return sum;
}
// Driver Code
public static void main (String[] args)
{
// Given String
String S = "abab";
System.out.println(countPalindromes(S));
}
}
// This code is contributed by code_hunt
Python3
# Python3 program the above approach
# Function to calculate the
# number of palindromes
def countPalindrome(S):
N = len(S)
Z = [0] * N
# Calculation of Z-array
l = 0
r = 0
for i in range(1, N):
if i <= r:
Z[i] = min(r - i + 1, Z[i - 1])
while((i + Z[i]) < N and (S[Z[i]] == S[i + Z[i]])):
Z[i] += 1
if ((i + Z[i] - 1) > r):
l = ir = i + Z[i] - 1
# Calculation of sigma(Z[i]+1)
sum = 0
for i in range(0, len(Z)):
sum += Z[i] + 1
# return the count
return sum
# Driver code
# Given String
S = "abab"
print(countPalindrome(S))
# This code is contributed by virusbuddah
C#
// C# program for the above approach
using System;
public class GFG{
// Function to calculate the
// number of palindromes
static int countPalindromes(String S)
{
int N = (int)S.Length;
int[] Z = new int[(N)];
// Calculation of Z-array
int l = 0, r = 0;
for(int i = 1; i < N; i++)
{
if (i <= r)
Z[i] = Math.Min(r - i + 1,
Z[i - l]);
while (i + Z[i] < N &&
S[Z[i]] ==
S[i + Z[i]])
{
Z[i]++;
}
if (i + Z[i] - 1 > r)
{
l = i;
r = i + Z[i] - 1;
}
}
// Calculation of sigma(Z[i]+1)
int sum = 0;
for(int i = 0; i < Z.Length; i++)
{
sum += Z[i] + 1;
}
// Return the count
return sum;
}
// Driver Code
public static void Main(String[] args)
{
// Given String
String S = "abab";
Console.WriteLine(countPalindromes(S));
}
}
// This code is contributed by 29AjayKumar
6
时间复杂度: O(N)
辅助空间: O(N)