Algorithm 如何避免生成所有子序列
可能重复:Algorithm 如何避免生成所有子序列,algorithm,dynamic-programming,Algorithm,Dynamic Programming,可能重复: 我一直在努力解决interviewstreet.com上的“”问题: 如果一个字符串可以通过连接同一字符串的两个副本来获得,则该字符串称为方形字符串。例如,“abab”、“aa”是方字符串,“aaa”、“abba”不是 给定一个字符串,该字符串有多少子序列是方字符串? 我尝试了一个DP解决方案,但这个约束似乎无法绕过:S最多有200个小写字符(a-z) 据我所知,查找长度n的列表的所有子序列是O(2^n),一旦n大于,比如说30,它就不再可行 如果n为200,是否真的可以系统地检查
我一直在努力解决interviewstreet.com上的“”问题: 如果一个字符串可以通过连接同一字符串的两个副本来获得,则该字符串称为方形字符串。例如,“abab”、“aa”是方字符串,“aaa”、“abba”不是 给定一个字符串,该字符串有多少子序列是方字符串? 我尝试了一个DP解决方案,但这个约束似乎无法绕过:
S最多有200个小写字符(a-z)
据我所知,查找长度n
的列表的所有子序列是O(2^n)
,一旦n
大于,比如说30,它就不再可行
如果n
为200,是否真的可以系统地检查所有解决方案?如何处理它?有许多算法(例如)可以在线性时间内生成前缀长度数组。也就是说,对于每个位置i,它告诉您从位置i开始可以读取的最长前缀是什么(当然,对于i=0,最长前缀是n)
现在请注意,如果有一个从开头开始的方形字符串,那么在这个前缀长度数组中有一个位置k,因此最长长度为>=k。所以你可以再次计算线性时间内的数字
然后删除字符串的第一个字母并执行相同的操作。
这个问题的总复杂度为O(n^2)。首先,对于每个字母
a..z
,您将在S
中获得它们的索引列表:
`p[x] = {i : S[i] = x}`, where `x = 'a',..,'z'`.
然后我们开始DP:
S: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
^ ^ ^
r1 l2 r2
设f(r1,l2,r2)
为任意长度L
的平方子序列(为方字符串的子序列)的数量
SS[L-1]=r1
SS[L]=l2
SS[2L-1]=r2
r1
处结束,后半部分正好在l2
处开始,并在r2
处结束
然后,算法是:
设f[r1,l2,l2]=1
如果S[r1]=S[l2]
,则为0
for (l2 in 1..2L-1 )
for( r1 in 0..l2-1 )
for (r2 in l2..2L-1)
if( f(r1, l2, r2) != 0 )
for (x in 'a'..'z')
for (i,j: r1 < i < l2, r2 < j, S[i] = S[j] = x) // these i,j are found using p[x] quickly
f[i, l2, j] += f[r1, l2, r2]
for(1..2L-1中的l2)
对于(0..l2-1中的r1)
用于(l2..2L-1中的r2)
如果(f(r1,l2,r2)!=0)
对于(a'中的x…'z')
对于(i,j:r1
最后,答案是f[,,.]
数组中所有值的总和
基本上,我们将S
unisgl2
分成两部分,然后计算公共子序列
我现在很难提供准确的时间复杂度估计,它肯定低于
n^4
,并且n^4
对于n=200
是可以接受的,但请注意,问题是要求子序列,而不是子字符串。例如,baba
包含3个方形子序列(baba
,bb
,aa
)。这也是一次面试,当然没人希望别人在面试中实现Z。interviewstreet.com不是面试lol:-)是的,你说得对。谢谢。同时我也发现了,所以我将检查它的复杂性。我现在没有足够的代表(=15
)来投票。@Dilbert,是的,很好,我认为这个答案有完全相同的想法,但它省略了“如何在给定的段中有效地找到相等的字母对”部分:我使用p[x]
为此,你甚至可以在p[x]
中使用二进制搜索。第二个:这个解决方案对数组还有一个维度:第一个序列的开始,这对我来说似乎是不必要的:它将时间和空间复杂度再乘以n
一次,这让它变得悲观(我不相信,它太粗糙了)n^6
@Dilbert,好的,n^4
现在。+1但200^4不是那么小。C#的时间限制是5秒,在我的1.6Ghz Core2duo上做一次200^4倍的乘法大约需要8秒,所以即使它能通过他们的测试,也将是一个非常接近的过程。我相信应该有一个时间复杂度更低的解决方案。@Dilbert,是的,有一个n^3
解决方案,也许我以后会编辑。你应该在问题中说明时间限制。请你将问题链接起来!