我有“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
但是当字符串的数量和字符串的长度更大时,这种方法会导致超时。
有没有更好的解决方法?
答案 0 :(得分:0)
此版本使用名为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))
答案 1 :(得分:0)
当前的方法有缺点,并且当检查解决方案是否不是回文时,大多数生成的解决方案最终被丢弃。
一个想法是,一旦您从一侧选择解决方案,您可以立即检查最后一组中是否有相应的解决方案。
例如,假设你的空间是这个
[["a","b","c"], ... , ["b","c","d"]]
我们可以看到,如果你选择" a"作为第一选择,没有" a"在最后一组中,这将排除所有可能以其他方式尝试的解决方案。
答案 2 :(得分:0)
对于较大的输入,您可以通过从第一个数组中获取单词来获得一些时间增益,并将它们与最后一个数组的单词进行比较,以检查这些对仍然允许形成回文,或者这样的组合通过从中间的其余单词插入数组,永远不会导致一个。
这样你可能会取消很多可能性,一旦你确定一对仍在运行中,这个方法可以递归重复。然后,您将保存两个单词的公共部分(当第二个单词反过来时),并将剩余的字母分开以便在递归部分中使用。
根据两个单词中哪一个更长,您可以将剩余的字母与左边或右边的数组中的单词进行比较。
这应该会在搜索树中进行大量的早期修剪。因此,您不会执行组合的完整笛卡尔积。
我还编写了函数来获取给定单词中的所有子字符串,这可能是您已经拥有的:
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倍:
上查看它当第一个数组具有多个具有相同字符串的条目(如示例数据中的'a'
)时,也可以在不重复搜索时找到一些增益。包含第二个'a'
的结果显然与第一个<div class = 'cell'>
...
<div class = 'image_container'>
...
<img ...>
</div>
</div>
相同。我没有对此优化进行编码,但可能会更好地提高性能。