Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在包含可能子序列列表的列表中查找可能回文字符串的算法_Python_Algorithm - Fatal编程技术网

Python 在包含可能子序列列表的列表中查找可能回文字符串的算法

Python 在包含可能子序列列表的列表中查找可能回文字符串的算法,python,algorithm,Python,Algorithm,我有“n”个字符串作为输入,我将这些字符串分成可能的子序列,如下所示 如果输入为:aa、b、aa 我创建一个如下所示的列表(每个列表都有字符串的子序列): 我想在列表中找到回文的组合。 例如,可能的回文是5-aba,aba,aba,aba,aabaa 这可以通过使用以下代码的暴力算法实现: d = [] def isPalindrome(x): if x == x[::-1]: return True else: return False for I in itertools.p

我有“n”个字符串作为输入,我将这些字符串分成可能的子序列,如下所示

如果输入为:aa、b、aa

我创建一个如下所示的列表(每个列表都有字符串的子序列)

我想在列表中找到回文的组合。 例如,可能的回文是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))
第二版 此版本使用名为
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”,这排除了所有可能以其他方式尝试的解决方案。

当前方法有缺点,并且当检查解决方案是否为回文时,大多数生成的解决方案最终被丢弃

一个想法是,一旦你们从一边选择了解决方案,你们就可以立即检查最后一组中是否有相应的解决方案

例如,让我们假设您的空间是这样的

[["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倍:

看到它继续运行了吗

另一个优化
当第一个数组有多个具有相同字符串的条目时,不重复搜索也会带来一些好处,比如示例数据中的
'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倍:

看到它继续运行了吗

另一个优化
当第一个数组有多个具有相同字符串的条目时,不重复搜索也会带来一些好处,比如示例数据中的
'a'
。包含第二个
'a'
的结果显然与第一个相同。我没有编写此优化代码,但这可能是一个更好地提高性能的想法。

d
列表吗?换一套。你可能大部分时间都在搜索
d
d是一个列表是的,我用它来避免检查一个已经计算过的字符串,如果它是回文,againIt检查一个项目是否在一个非常慢的列表中