有一种动态规划算法用于计算字符串的回文子序列的数量;您可以使用它来计算非回文子序列的数量,方法是从子序列的数量(即 2 n)中减去回文子序列的数量。O(n2)
该算法按 OP 中的标准对子序列进行计数;如果用于选择元素的索引列表存在差异,则认为两个子序列不同,即使结果子序列具有相同的元素。
为了计算回文子序列,我们根据序列的间隔建立计数。具体来说,我们定义:
Si,j
=S
从 index 开始到 indexi
结束的子串j
(含)
Pi,j
= 的回文子序列的数量Si,j
现在,每个单元素区间都是回文,所以:
Pi,i = 1
对所有人i < n
如果子串不是以相同的元素(即)开始和结束,则回文子序列包括:Si ≠ Sj
包含但不包含的Si
Sj
包含但不包含的Sj
Si
既不包含也不包含Si
Sj
现在,注意包括第一组和第三组子序列,同时包括第二组和第三组;正好是第三组。最后:Pi,j-1
Pi+1,j
Pi+1,j-1
Pi,j = Pi+1,j + Pi,j-1 − Pi+1,j-1
如果Si ≠ Sj
但万一呢?在这种情况下,我们必须添加由 组成的回文,后跟来自 的子序列回文,以及仅由开始和结束字符组成的回文子序列。(从技术上讲,一个空序列是一个回文,但我们在这里不计算它们。)我们添加的子序列的数量是 P i+1,j-1 + 1,这抵消了上面等式中减去的双重计数。所以:Si = Sj
Si
Si+1,j-1
Sj
Pi,j = Pi+1,j + Pi,j-1 + 1
如果.Si = Sj
为了节省空间,我们实际上可以计算增加的值;我们只需要保留其中两个向量即可生成最终结果 P 0,|S|-1。Pi,i+k for 0 ≤ i < |S|-k
k
编辑:
这是一个小python程序;第一个计算回文子序列的数量,如上所述,驱动程序计算非回文子序列的数量(即删除零个或多个元素并产生非回文的方法的数量;如果原始序列是回文,那么它是删除一个或多个元素的方法数。)
# Count the palindromic subsequences of s
def pcount(s):
length = len(s)
p0 = [0] * (length + 1)
p1 = [1] * length
for l in range(1, length):
for i in range(length - l):
p0[i] = p1[i]
if s[i] == s[i + l]:
p1[i] += p1[i+1] + 1
else:
p1[i] += p1[i+1] - p0[i+1]
# The "+ 1" is to account for the empty sequence, which is a palindrome.
return p1[0] + 1
# Count the non-palindromic subsequences of s
def npcount(s):
return 2**len(s) - pcount(s)