如何找到最长的上升子串(或绑定的子串)?

时间:2013-10-29 12:33:48

标签: python

如何定义一个反复出现的函数 findmax ,其作用如下:

findmax('abc')-->['abc']
findmax('afz')-->['afz']
findmax('cba')-->['c','b','a']
findmax('zfa')-->['z','f','a']
findmax('abczabc')-->['abcz']
findmax('abcabc')-->['abc','abc']

该函数仅显示一个或多个a-z字符。并返回字符按升序排列的所有最长子字符串。

为什么我问这个问题?因为我的直觉告诉我必须有一个优雅的回归式解决方案。但令人遗憾的是,我无法解决这个问题。

请看一下我写的可怕解决方案:

def findmax(s):
    res=[]
    string=s[0]
    end=len(s)
    for i in range(1,end):
        if ord(s[i-1])<=ord(s[i]):
            string+=s[i]
            if i==end-1:
                res.append(string)                
        else:
            res.append(string)
            string=s[i]
            if i==end-1:
                res.append(string)
    fin=[]
    maxNum=0
    for r in res:
        size=len(r)
        if size>maxNum:
            maxNum=size
            fin=[]
            fin.append(r)
        elif size==maxNum:
            fin.append(r)                    
    return fin

5 个答案:

答案 0 :(得分:3)

如果你真的想要一个递归式的功能。我不知道它是否更优雅,但我知道它不如命令式(递归限制和尾部调用)更有效且更有限:

from collections import defaultdict

'''
    Return the "biggest" key (assuming keys are int).
    Should've used a ordered set instead of a dict
'''
def maxkey(dictio):
    return max ([ int(k) for k in dictio.keys() ])

'''
    Recursion-style of findmax. Notice the call to the same input string minus the first element,
    which indicate that the recursion isn't really much more efficient than imperative style.
    Also we have to take the maximum recursion limit into account (which should be attained in practice.)
'''
def findmax( input_string , tempbuffer = defaultdict(list), temp = '' ):

    # End of the recursion
    if len(input_string) == 0:
        tempbuffer[len(temp)].append(temp)          # add last element
        output = tempbuffer[maxkey(tempbuffer)]     # return the set of longest elements
        tempbuffer.clear()                          # pesky little mutable objects ...
        return output

    # Still elements in the input string
    else:
        first_char = input_string[0]

        # still ascending : buffering
        if len(temp) == 0 or first_char > temp[-1]:
            temp   = temp + first_char
        # new string : store the old one
        else:
            tempbuffer[len(temp)].append(temp)
            temp   = first_char

        # Recursion call on the 'tail' of the input string, one character at a time
        return findmax( input_string[1:],tempbuffer, temp)




if __name__ == '__main__' :

    print findmax('abczabc')

    print findmax('abcabd')

答案 1 :(得分:1)

根本不需要递归。

def findmax(s):
    matches = []
    current = [s[0]]
    for index, character in enumerate(s[1:]):
        if character >= s[index]:
            current.append(character)
        else:
            matches.append(current)
            current = [character]
    matches.append(current)
    maxlen = len(max(matches, key=len))
    return ["".join(match) for match in matches if len(match)==maxlen]

测试用例:

>>> findmax('abc')
['abc']
>>> findmax('afz')
['afz']
>>> findmax('cba')
['c', 'b', 'a']
>>> findmax('zfa')
['z', 'f', 'a']
>>> findmax('abczabc')
['abcz']
>>> findmax('abcabc')
['abc', 'abc']

Explanation can be found here(稍微修改了此代码版本)。

答案 2 :(得分:1)

以下是递归解决方案。这个函数纯粹是递归的,不是循环,或者根本没有循环:

def find_max(s):
    _ret = []

    def string_iter(concat, compare):

        def appender():
            if len(concat) >= len(_ret[-1]):
                if len(concat) > len(_ret[-1]):
                    while _ret:
                        _ret.pop()
                _ret.append(concat)

        if len(compare) == 0:
            if len(_ret) != 0:
                appender()
            else:
                _ret.append(concat)
            return

        if concat[-1] < compare[0]:
            concat += compare[0]
            string_iter(concat, compare[1:])
        else:
            if len(_ret) != 0:
                appender()
            else:
                _ret.append(concat)
            string_iter(compare[0], compare[1:])

    string_iter(s[0], s[1:])

    return _ret

print find_max('abc')      # -->['abc']
print find_max('afz')      # -->['afz']
print find_max('cba')      # -->['c','b','a']
print find_max('zfa')      # -->['z','f','a']
print find_max('abczabc')  # --> ['abcz']
print find_max('abcabcpaidfbkjabdsfilabdfkabldfjadf')   # --> ['abcp', 'abdfk']

答案 3 :(得分:0)

改编my solution to a previous answer

import string

def findmax(s):
    groups = []
    cur_longest = ''
    prev_char = ''
    for c in map(string.lower, s):
        if prev_char and c < prev_char:
            groups.append(cur_longest)
            cur_longest = c
        else:
            cur_longest += c
        prev_char = c
    groups.append(cur_longest)
    length = max([len(g) for g in groups])
    return [group for group in groups if len(group) == length]

使用它:

>>> findmax('abc') # expect: ['abc']
['abc']
>>> findmax('afz') # expect: ['afz']
['afz']
>>> findmax('cba') # expect: ['c','b','a']
['c', 'b', 'a']
>>> findmax('zfa') # expect: ['z','f','a']
['z', 'f', 'a']
>>> findmax('abczabc') # expect: ['abcz']
['abcz']
>>> findmax('abcabc') # expect: ['abc','abc']
['abc', 'abc']

答案 4 :(得分:0)

在研究了georgesl和Games Brainiac的两个答案后,我得到了一个更加满意的解决方案,结合了它们的两个优点。

它们都在结构上设计得很好。

我认为georgesl的优点是:tempbuffer dict对象的设计,而Games Brainiac的设计是:closure的设计。

虽然效果不太好,但我仍然很高兴有一个简单而优雅的解决方案。

所以,我想在此分享:

from collections import defaultdict

def findmax(s):
    buf=defaultdict(list)
    def recur(s,mbr):
        if s=='':
            buf[len(mbr)].append(mbr)
            return buf[max(buf)]
        else:
            head=s[0]
            if mbr=='' or mbr[-1]<head:
                mbr=mbr+head
            else:
                buf[len(mbr)].append(mbr)
                mbr=head
            return recur(s[1:],mbr)
    return recur(s,'')

if __name__ == '__main__' :
    print 'abc',findmax('abc')
    print 'afz',findmax('afz') 
    print 'abcabcda',findmax('abcabcda')
    print 'abczabcdabcd',findmax('abczabcdabcd')               
    print 'zfa',findmax('zfa')
    print 'zfa',findmax('zfa')

以下是结果:

>>> 
abc ['abc']
afz ['afz']
abcabcda ['abcd']
abczabcdabcd ['abcz', 'abcd', 'abcd']
zfa ['z', 'f', 'a']
zfa ['z', 'f', 'a']