如何定义一个反复出现的函数 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
答案 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']