[英]Algorithm for finding the possible palindromic strings in a list containing a list of possible subsequences
我有“n”个字符串作为输入,我将可能的子序列分成如下所示的列表
如果输入是:aa,b,aa
我创建一个如下所示的列表( 每个列表都有字符串的子序列 ):
aList = [['a', 'a', 'aa'], ['b'], ['a', 'a', 'aa']]
我想在aList中找到列表中的回文组合 。 例如,可能的回文可能是5 - aba,aba,aba,aba,aabaa
这可以通过使用以下代码的强力算法来实现:
d = []
def isPalindrome(x):
if x == x[::-1]: return True
else: return False
for I in itertools.product(*aList):
a = (''.join(I))
if isPalindrome(a):
if a not in d:
d.append(a)
count += 1
但是当字符串的数量和字符串的长度更大时,这种方法会导致超时。
有没有更好的方法来解决这个问题?
此版本使用一个名为seen
的集合,以避免多次测试组合。
请注意,您的函数isPalindrome()
可以简化为单个表达式,因此我将其删除并仅进行内联测试以避免不必要的函数调用的开销。
import itertools
aList = [['a', 'a', 'aa'], ['b'], ['a', 'a', 'aa']]
d = []
seen = set()
for I in itertools.product(*aList):
if I not in seen:
seen.add(I)
a = ''.join(I)
if a == a[::-1]:
d.append(a)
print('d: {}'.format(d))
当前的方法具有缺点,并且当检查解决方案是否是回文时,大多数生成的解决方案最终被丢弃。
一个想法是,一旦您从一侧选择解决方案,您可以立即检查最后一组是否有相应的解决方案。
例如,假设你的空间就是这个
[["a","b","c"], ... , ["b","c","d"]]
我们可以看到,如果您选择“a”作为首选,则最后一组中没有“a”,这将排除所有可能以其他方式尝试的解决方案。
对于较大的输入,您可以通过从第一个数组中获取单词来获得一些时间增益,并将它们与最后一个数组的单词进行比较,以检查这些对仍然允许形成回文,或者这样的组合永远不会导致通过从中间的其余单词插入数组来实现一个。
这样你就可以取消很多可能性,一旦你确定一对仍然在运行中,这个方法可以递归地重复。 然后,您将保存两个单词的公共部分(当第二个单词反过来时),并将剩余的字母分开以便在递归部分中使用。
根据两个单词中哪一个更长,您可以将剩余的字母与下一个左边或右边的数组中的单词进行比较。
这应该会在搜索树中进行大量的早期修剪。 因此,您不会执行组合的完整笛卡尔积。
我还编写了函数来获取给定单词的所有子字符串,这可能是您已经拥有的:
def allsubstr(str):
return [str[i:j+1] for i in range(len(str)) for j in range(i, len(str))]
def getpalindromes_trincot(aList):
def collectLeft(common, needle, i, j):
if i > j:
return [common + needle + common[::-1]] if needle == needle[::-1] else []
results = []
for seq in aRevList[j]:
if seq.startswith(needle):
results += collectRight(common+needle, seq[len(needle):], i, j-1)
elif needle.startswith(seq):
results += collectLeft(common+seq, needle[len(seq):], i, j-1)
return results
def collectRight(common, needle, i, j):
if i > j:
return [common + needle + common[::-1]] if needle == needle[::-1] else []
results = []
for seq in aList[i]:
if seq.startswith(needle):
results += collectLeft(common+needle, seq[len(needle):], i+1, j)
elif needle.startswith(seq):
results += collectRight(common+seq, needle[len(seq):], i+1, j)
return results
aRevList = [[seq[::-1] for seq in seqs] for seqs in aList]
return collectRight('', '', 0, len(aList)-1)
# sample input and call:
input = ['already', 'days', 'every', 'year', 'later'];
aList = [allsubstr(word) for word in input]
result = getpalindromes_trincot(aList)
我做了一个与martineau发布的解决方案的时间比较。 对于我使用的样本数据,此解决方案的速度提高了约100倍:
看它在repl.it上运行
当第一个数组具有多个具有相同字符串的条目(如示例数据中的'a'
时,也可以在不重复搜索时找到一些增益。 包含第二个'a'
的结果显然与第一个'a'
相同。 我没有对此优化进行编码,但可能更想提高性能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.