Python 优化求解回文的时间/空间复杂性

Python 优化求解回文的时间/空间复杂性,python,performance,optimization,Python,Performance,Optimization,Twitter最近提出了这个问题: 回文是一系列前后读相同内容的字符。给定一个字符串s,查找s中最长的回文子字符串 例如: Input: "banana" Output: "anana" Input: "million" Output: "illi" 所以我就这样解决了 class Solution: def longestPalindrome(self, s): index = 0

Twitter最近提出了这个问题:

回文是一系列前后读相同内容的字符。给定一个字符串s,查找s中最长的回文子字符串

例如:

Input: "banana"
Output: "anana"

Input: "million"
Output: "illi"

所以我就这样解决了

class Solution: 
    def longestPalindrome(self, s):
        index = 0
        longestPalindrome = ""
        for x  in s:
            subStr = s[index + 1:]
            nextIndex = subStr.find(x)
            while nextIndex != -1:
                txt = x + subStr
                pland = txt[:nextIndex + 2]
                if self.isPalindromicSubString(pland):
                    if len(pland) > len(longestPalindrome):
                        longestPalindrome = pland
                nextIndex = subStr.find(x,nextIndex + 1)
            index = index + 1
        return longestPalindrome

    def isPalindromicSubString(self,subStr):
        index = 0
        reverseIndex = -1
        isItPalindromic = True
        for y in subStr:
            if y != subStr[reverseIndex]:
               isItPalindromic = False
            index = index + 1
            reverseIndex = reverseIndex - 1  
        return isItPalindromic

# Test program
s = "abcdef aka"
print(str(Solution().longestPalindrome(s)))
# racecar

它工作正常,时间复杂度为O(N^2)
有没有办法做得更好,给我你对时间和空间复杂性的意见首先,我不知道你为什么要用clas来做这个。在python中,如果不使用OOP,我们不会编写类,而您不是

简介 我经过了将是回文的子字符串*1,
从中间向左移动,直到子字符串不再是回文
否则,字符串的末尾将被满足

代码
def find_longest_p(s):
pal_start=0;pal_end=1#最长的索引
对于范围(0,len(s)*2-1)内的半_指数:
#关于第1范围边界
#它经过回文的中间部分
#在某个字符或2个字符之间
#这个字符是s[half_index/2]
#其中,对于奇数,它是s[x.5],表示s[x]a和s[x+1]
c=b=-1#以值开始,因为for else要求b,c
对于范围内的b((半索引+半索引%2)//2-1,-1,-1):
#从左边的第一个索引开始,到0
#“a b c d”(str“abcd”,忽略空格)
#0123456(半指数)
#对于半指数==4
#b开始->1->0
#对于半指数==3
#b开始->1->0
c=半指数-b#b的对称指数
如果cpal\U end-pal\U start:
pal_start=b+1
pal_end=c
打破
其他:
#左边禁区
#算术有点变化
长度=c-b+1
如果长度>pal\U end-pal\U start:
pal_start=b
pal_end=c+1
返回s[pal\u开始:pal\u结束]
复杂性 这似乎有O(n^2)
事实并非如此,因为在一个普通字符串中,回文不多。
这意味着第二个循环通常只有一次迭代
花费O(n)时间复杂性,
和额外的O(1)空间,定义了3个变量和一些中间产品,
或者O(n)空格如果包含复制和切片(这是不可避免的)

脚注 *1回文的中间可以在某个索引处,也可以在两个索引之间
因此,我通过了双重索引
中间值应该是:0,0.5,1,1.5,…

我先说:0,1,2,3,…

我不知道你为什么要用clas来做这个。在python中,如果不使用OOP,我们不会编写类,而您不是

简介 我经过了将是回文的子字符串*1,
从中间向左移动,直到子字符串不再是回文
否则,字符串的末尾将被满足

代码
def find_longest_p(s):
pal_start=0;pal_end=1#最长的索引
对于范围(0,len(s)*2-1)内的半_指数:
#关于第1范围边界
#它经过回文的中间部分
#在某个字符或2个字符之间
#这个字符是s[half_index/2]
#其中,对于奇数,它是s[x.5],表示s[x]a和s[x+1]
c=b=-1#以值开始,因为for else要求b,c
对于范围内的b((半索引+半索引%2)//2-1,-1,-1):
#从左边的第一个索引开始,到0
#“a b c d”(str“abcd”,忽略空格)
#0123456(半指数)
#对于半指数==4
#b开始->1->0
#对于半指数==3
#b开始->1->0
c=半指数-b#b的对称指数
如果cpal\U end-pal\U start:
pal_start=b+1
pal_end=c
打破
其他:
#左边禁区
#算术有点变化
长度=c-b+1
如果长度>pal\U end-pal\U start:
pal_start=b
pal_end=c+1
返回s[pal\u开始:pal\u结束]
复杂性 这似乎有O(n^2)
事实并非如此,因为在一个普通字符串中,回文不多。
这意味着第二个循环通常只有一次迭代
花费O(n)时间复杂性,
和额外的O(1)空间,定义了3个变量和一些中间产品,
或者O(n)空格如果包含复制和切片(这是不可避免的)

脚注 *1回文的中间可以在某个索引处,也可以在两个索引之间
因此,我通过了双重索引
中间值应该是:0,0.5,1,1.5,…

我去了:0,1,2,3,…

这里是Manacher算法的python实现,来自Kevin链接的

def最长回文子串(s:str)->str:
#在s的字符之间和s的周围添加哨兵字符,以处理等长回文
#无需边界检查即可退出回文扩展循环的不同外字符
#以防整个字符串是回文
带|边界=“@|”+“|”。加入(s)+“|!”
#以新字符串中每个索引为中心的回文长度
回文长度=[0表示有边界的回文长度]
#当前回文中心
中心电流=0
#cu的右边界
class Solution: 
    def longestPalindrome(self, s):
        index = 0
        longestPalindrome = ""
        for x  in s:
            subStr = s[index + 1:]
            nextIndex = subStr.find(x)
            while nextIndex != -1:
                txt = x + subStr
                pland = txt[:nextIndex + 2]
                if self.isPalindromicSubString(pland):
                    if len(pland) > len(longestPalindrome):
                        longestPalindrome = pland
                nextIndex = subStr.find(x,nextIndex + 1)
            index = index + 1
        return longestPalindrome

    def isPalindromicSubString(self,subStr):
        index = 0
        reverseIndex = -1
        isItPalindromic = True
        for y in subStr:
            if y != subStr[reverseIndex]:
               isItPalindromic = False
            index = index + 1
            reverseIndex = reverseIndex - 1  
        return isItPalindromic

# Test program
s = "abcdef aka"
print(str(Solution().longestPalindrome(s)))
# racecar

# Question: https://stackoverflow.com/questions/62838784/optimize-time-space-complexity-for-solving-palindromes

import re
import time


def longestPalindrome(string, longest_first=True):
    palindrome = None
    order = range(len(string)//2, -1, -1) if longest_first else range(1, len(string)//2+1)
    for n in order:
        # Example: re.sub(r'^.*(\w)(\w)(\w)(\w)(\w)?\3\2\1.*$', r'\1\2\3\4\3\2\1', s)
        regex_match = "".join([
            r'^.*',
            r'(\w)' * n,
            r'(\w)?',
            ''.join([ f'\\{i}' for i in range(n,0,-1) ]),
            r'.*$'
        ])
        if re.match(regex_match, string):
            regex_replace = "".join([ f'\\{i}' for i in list(range(1,n+2))+list(range(n,0,-1)) ])
            palindrome    = re.sub(regex_match, regex_replace, string)
            if longest_first:
                return palindrome  # return the first match
        else:
            if not longest_first:
                break  # return the last match

    return palindrome


if __name__ == '__main__':
    for longest_first in [True, False]:
        print(f'\nLongest First = {longest_first}')
        for sentence in [
            "banana",
            "tracecars",
            "detartrated",
            "saippuakivikauppias",
            "this is not the palindrome you are looking for"
        ]:
            start_time = time.perf_counter()
            answer     = longestPalindrome(sentence, longest_first)
            time_taken = time.perf_counter() - start_time
            print(f'len({len(sentence):2d}) in {1000*time_taken:6.2f}ms = longestPalindrome({sentence}, {longest_first}) == {answer}')

    assert longestPalindrome("banana")      == "anana"
    assert longestPalindrome("tracecars")   == "racecar"
    assert longestPalindrome("detartrated") == "detartrated"

Longest First = True
len( 6) in   0.79ms = longestPalindrome(banana, True) == anana
len( 9) in   0.39ms = longestPalindrome(tracecars, True) == racecar
len(11) in   0.41ms = longestPalindrome(detartrated, True) == detartrated
len(19) in   0.59ms = longestPalindrome(saippuakivikauppias, True) == saippuakivikauppias
len(46) in  13.19ms = longestPalindrome(this is not the palindrome you are looking for, True) == oo

Longest First = False
len( 6) in   0.06ms = longestPalindrome(banana, False) == anana
len( 9) in   0.08ms = longestPalindrome(tracecars, False) == racecar
len(11) in   0.19ms = longestPalindrome(detartrated, False) == detartrated
len(19) in   0.46ms = longestPalindrome(saippuakivikauppias, False) == saippuakivikauppias
len(46) in   0.04ms = longestPalindrome(this is not the palindrome you are looking for, False) == oo