用函数式和命令式两种风格完成一道算法题

昨天偶然看见一个算法题,要求返回一个包含给定英文字符串(小写)中所有最长的升序字符串的列表,比如:

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

其实用常规思路来解还是没什么难度的.不过最近在学Scheme,便总是想着用函数式风格该怎么搞.最好能够完全避开赋值语句.

现在终于彻彻底底搞出来了,还是2种版本的函数式风格.纯的那种就是完全没有任何赋值语句的,甚至连方法语句都没有的(比如list.append(1)之类的).

感觉函数式编程很考验"倒推"以及"把复杂问题分解为简单问题'的能力.所谓"倒推",就是事先心中要设计好一个算法框架和数据结构(字典,列表,集合等等).命令式编程很难体会到设计的概念,大概是因为可以把一个变量改来改去,比较容易.

有时候我们需要的是某种值,这些值直接求是非常难的.但是把它转化成某种常见数据结构的衍生品,往往会变得简单.

 # -*- coding:utf-8 -*-
from collections import defaultdict

#常规命令式 
def findmax_c(s):
    buf=defaultdict(list)
    string=s if len(s)<2 else s[0]
    for i in range(1,len(s)):
        if s[i-1]<=s[i]:
            string+=s[i]           
        else:
            buf[len(string)].append(string)
            string=s[i]
    buf[len(string)].append(string)               
    return buf[max(buf)]

#不是那么纯的函数式:
def findmax_f(s):
    def recur(s,mbr='',buf=defaultdict(list)):
        if s=='':
            buf[len(mbr)].append(mbr)
            return buf[max(buf)]
        if mbr=='' or mbr[-1]<=s[0]:
            return recur(s[1:],mbr+s[0])
        buf[len(mbr)].append(mbr)
        return recur(s[1:],s[0])
    return recur(s)

def memory(function):
    cache = {}
    def memofunc(*nkw,**kw):
        key=str(nkw)+str(kw)
        if key not in cache:            
            cache[key] = function(*nkw,**kw)
        return cache[key]
    return memofunc

#纯函数式:
def findmax_pf(s):
    @memory
    def recur(s,mbr=''):
        if s=='':
            return [mbr]    
        if mbr=='' or mbr[-1]<=s[0]:
            return recur(s[1:],mbr+s[0])
        return [mbr]+recur(s[1:],s[0])
    return filter(lambda x:len(x)==len(max(recur(s),key=len)) ,recur(s))



if __name__ == '__main__' :
    for x in ['','a','aggz','abcaggza','abcabc','zfa','zfa']:
        print '字符:{}命令式:{}函数式:{}纯函数:{}'.format(
            x.ljust(10),
            str(findmax_c(x)).ljust(16),
            str(findmax_f(x)).ljust(16),
            str(findmax_pf(x)).ljust(16))

最终结果:

>>> 
字符:          命令式:['']            函数式:['']            纯函数:['']            
字符:a         命令式:['a']           函数式:['a']           纯函数:['a']           
字符:aggz      命令式:['aggz']        函数式:['aggz']        纯函数:['aggz']        
字符:abcaggza  命令式:['aggz']        函数式:['aggz']        纯函数:['aggz']        
字符:abcabc    命令式:['abc', 'abc']  函数式:['abc', 'abc']  纯函数:['abc', 'abc']  
字符:zfa       命令式:['z', 'f', 'a'] 函数式:['z', 'f', 'a'] 纯函数:['z', 'f', 'a'] 
字符:zfa       命令式:['z', 'f', 'a'] 函数式:['z', 'f', 'a'] 纯函数:['z', 'f', 'a']

其中,装饰器memory主要是让Python避免重复计算相同参数的函数..这是提高性能必须采取的手段,因为函数式编程要求你不能对一个值建立引用.

函数式编程要在默认参数上大做文章..通常命令式编程中的一些变量可以把它转化为默认参数来处理.

原文地址:https://www.cnblogs.com/xiangnan/p/3397151.html