微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

寻找最长回文子串的最优蛮力解决方案

如何解决寻找最长回文子串的最优蛮力解决方案

这是我目前的方法

def ispalindrome(s):
    if (s[::-1] == s):
        return True
    return False

def solve(s):
    l = len(s)
    ans = ""
    
    for i in range(l):
        subStr = s[i]
        for j in range(i + 1,l):
            subStr += s[j]
            if (j - i + 1 <= len(ans)):
                continue
            if (ispalindrome(subStr)):
                ans = max(ans,subStr,key=len)

    return ans if len(ans) > 1 else s[0]

print(solve(input()))

我的代码超过了自动评分系统的时间限制。我已经花了一些时间在谷歌上查找,我发现的所有解决方案都有相同的想法,没有优化或使用动态编程,但遗憾的是我必须并且只使用蛮力来解决这个问题。我试图通过跳过比最后找到的最长回文字符串短的所有子字符串来更早地打破循环,但最终仍无法满足时间要求。有没有其他方法可以比上述方法更早或更省时地打破这些循环?

解决方法

使用 subStr += s[j],在前一个 subStr 的长度上创建一个新字符串。并且使用 s[::-1],来自前一个偏移量 j 的子字符串被一遍又一遍地复制。两者都是低效的,因为字符串在 Python 中是不可变的,并且必须被复制为任何字符串操作的新字符串。最重要的是,s[::-1] == s 中的字符串比较也效率低下,因为您已经在之前的迭代中比较了所有内部子字符串,并且只需要比较当前偏移量处最外面的两个字符。

您可以只跟踪到目前为止最长回文的索引和偏移量,并且只在返回时对字符串进行切片。要考虑奇数和偶数长度的回文,您可以将索引一次增加 0.5,或者将长度加倍以避免必须处理浮点到整数的转换:

def solve(s):
    length = len(s) * 2
    index_longest = offset_longest = 0
    for index in range(length):
        offset = 0
        for offset in range(1 + index % 2,min(index,length - index),2):
            if s[(index - offset) // 2] != s[(index + offset) // 2]:
                offset -= 2
                break
        if offset > offset_longest:
            index_longest = index
            offset_longest = offset
    return s[(index_longest - offset_longest) // 2: (index_longest + offset_longest) // 2 + 1]
,

对代码的这种修改应该会提高性能。当最大可能的子字符串小于您已经计算出的答案时,您可以停止您的代码。此外,您应该使用 j+ans+1 而不是 j+1 开始第二个循环,以避免无用的迭代:

def solve(s):
    l = len(s)
    ans = ""
    
    for i in range(l):
        if (l-i+1 <= len(ans)):
            break
        subStr = s[i:len(ans)]
        for j in range(i + len(ans) + 1,l+1):
            if (isPalindrome(subStr)):
                ans = subStr
            subStr += s[j]
    return ans if len(ans) > 1 else s[0]
,

通过使用“扩展中心”方法解决,感谢@Maruthi Adithya

,

这是一个时间复杂度高于所提供解决方案的解决方案。

注:本帖是为了更好的思考问题,不具体回答问题。我采用数学方法找到大于 2^L 的时间复杂度(其中 L 是输入字符串的大小)

注意:这是一篇讨论潜在算法的帖子。你不会在这里找到答案。此处显示的逻辑尚未得到广泛证明。 如果有什么我没有考虑过,请告诉我。

方法: 创建一组可能的子串。比较并从该集合中找出具有最高可能回文数的最大对*。

输入字符串示例:“abc”。

在这个例子中,子串集有:"a","b","c","ab","ac","bc","abc"。

  • 7 个元素。

将每个元素与所有其他元素进行比较将涉及:7^2 = 49 次计算。

因此,输入大小为 3,计算次数为 49。

时间复杂度

首先计算生成子串集的时间复杂度:

<a href="https://www.codecogs.com/eqnedit.php?latex=\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)" title="\sum_{a=1}^{L}\left ( C_{a}^{L} \right )" /></a>

(数学方程式显示在代码片段中)

这里,我们将输入大小 L 中所有不同的子串大小组合相加。

明确地说:在上面的例子中,输入大小是 3。所以我们找到所有大小为 1 的对(即:“a”、“b”、“c”)。然后大小 =2(即:“ab”、“ac”、“bc”),最后大小 = 3(即:“abc”)。

  1. 因此从输入字符串中选择 1 个字符 = 一次取 L 个事物 1 的组合,而不重复。 在我们的例子中,组合数 = 3。 这可以在数学上表示为(其中 a = 1):

<a href="https://www.codecogs.com/eqnedit.php?latex=C_{a}^{L}" target="_blank"><img src="https://latex.codecogs.com/gif.latex?C_{a}^{L}" title="C_{a}^{L}" /></a>

  1. 同样从输入字符串中选择 2 个字符 = 3
  2. 从输入字符串中选择 3 个字符 = 1

从最大长度的生成集合中寻找回文对的时间复杂度: 生成集大小:N 为此,我们必须将集合中的每个字符串与集合中的所有其他字符串进行比较。

所以 N*N,或 2 个 for 循环。因此最终的时间复杂度为:

<a href="https://www.codecogs.com/eqnedit.php?latex=\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)^{2}" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\sum_{a=1}^{L}\left&space;(&space;C_{a}^{L}&space;\right&space;)^{2}" title="\sum_{a=1}^{L}\left ( C_{a}^{L} \right )^{2}" /></a>

对于 L > 1,这是大于 2^L 的发散函数。

但是,可以对此应用多种优化。例如:没有必要将“a”与“abc”进行比较,因为“a”也会与“a”进行比较。即使应用了这种优化,它的时间复杂度仍然会 > 2^L(大多数情况下)。

希望这能让你对这个问题有一个新的看法。

PS:这是我的第一篇文章。

,

您不应该从该字符串的开头找到该字符串,而应该从它的中间开始并展开当前字符串

例如,对于字符串 xyzabccbalmn,您的解决方案将花费 ~ 6 * 11 次比较,但从中间搜索将花费 ~ 11 * 2 + 2 次操作

但无论如何,暴力破解永远无法确保您的解决方案对于任何任意字符串都运行得足够快。

,

试试这个:

def solve(s):
    if len(s)==1:
        print(0)
        return '1'
    if len(s)<=2 and not(isPalindrome(s)):
        print (0)
        return '1'
    elif isPalindrome(s):
        print( len(s))
        return '1'
    elif isPalindrome(s[0:len(s)-1]) or  isPalindrome(s[1:len(s)]):
          print (len(s)-1)
          return '1'
    elif  len(s)>=2:      
         solve(s[0:len(s)-1])
         return '1'
    return 0

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。