Cryptarithmetic Problem ‘ODD+ODD == EVEN’
这段代码不仅仅是针对一个‘ODD+ODD==EVEN’,更重要的是它可以针对很多这种类型的等式,来寻找可能的数字数字表示。例如:‘655+655=1310’
from __future__ import division #在python2版本中,3/2返回1,而在python3版本中却返回1.5,在这个问题中,我们需要1.5作为结果,但是我们又用的是python2,故添加这一句来转化
import string, re, itertools
def solve(formula):
"""Given a formula like 'ODD + ODD == EVEN', fill in digits to solve it.
Input formula is a string; output is a digit-filled-in string or None."""
for f in fill_in(formula):
if valid(f):
return f
def fill_in(formula):
"Generate all possible fillings-in of letters in formula with digits."
letters = ''.join(set(re.findall('[A-Z]',formula))) #should be a string
for digits in itertools.permutations('1234567890', len(letters)):
table = string.maketrans(letters, ''.join(digits))
yield formula.translate(table)
def valid(f):
"""Formula f is valid if and only if it has no
numbers with leading zero, and evals true."""
try:
return not re.search(r'\b0[0-9]', f) and eval(f) is True
except ArithmeticError:
return False
注解:
- valid()函数:判断一个数是否是正确格式的数,若是,则返回True,否则返回False。该函数把以0开头的数字去除掉了,因为以0开头的数字在计算机中是以八进制进行识别的,不符合我们解决这个问题的规则。
- fill_in()函数:该函数是一个生成器函数,返回一个数字等式对应于输入的字母等式字符串。
(i)若输入是‘ODD+ODD==EVEN’,那么letters=‘ODEVN’这样一个字符串。join是字符串的一个方法,把join括号里面的东西连接成一个字符串。
(ii)**set()**返回一个集合,集合的概念类似我们高中时期学的数学概念集合,有一篇博客写得不错,适合入门set,如果有对set不是很清楚地可以参考:
https://www.cnblogs.com/SmallWZQ/p/8488744.html
(iii)re.findall(’[A-Z]’,formula) 这一部分查找formula里面所有的大写字母,这一部分是正则表达式模块的内容
(iv)itertools.permutations(‘1234567890’,len(letters)),这一部分返回的是所有len(letters)长度的数字的全排列。对这个例子来讲,letters的长度是5,所以我们从0-9这10个数字中任选5个全排列,返回所有的可能性。
(v)maketrans(from,to),该方法接收两个参数,返回一个转换表。该表将把from中的每个字符映射到to中相同位置的字符中;from和to的长度必须相同。
(vi)string.translate(table,delete_string), 该方法接受一个由上述maketrans()方法创建的table和一个将要被删除的字符串,先将string中匹配到的delete_string删除掉,然后再将string中的‘from’替换成‘to’(from和to如前所述)。当然,第二个参数可以省略。 - slove()函数:检查fill_in()函数返回的等式中的数字是否符合正确的数字规则。
- 上述代码仅仅返回了一种可能性,若是把所有的可能性都打印出来,那么我们只需要把solve()函数中的return改成print就可以了,因为外层是一个for循环,他会一直打印结果直到结束,而不是碰到第一个结果就return了。
把‘YOU’变成‘(1*U+10*O+100*Y)
’
def compile_word(word):
"""Compile a word of uppercase letters as numeric digits.
E.g., compile_word('YOU') => '(1*U+10*O+100*Y)'
Non-uppercase words uncahanged: compile_word('+') => '+'"""
if word.isupper():
terms = [('%s*%s' % (10 ** i, d))
for (i, d) in enumerate(word[::-1])]
return '(' + '+'.join(terms) + ')'
else:
return word
map()
- map() 是python内置的高阶函数,他接受一个函数f和一个或多个list,并通过把函数f依次作用在list的每个元素上,得到一个新的object并返回。不改变原来的list(注:python2返回列表,python3返回迭代对象即object)
res = map(compile_word, ['YOU', 'ME', 'you'])
print(res)
print(list(res))
>>><map object at 0x000001B2E47EE908> # 迭代对象
>>>['(1*U+10*O+100*Y)', '(1*E+10*M)', 'you'] # 将其转化为列表
# 也可以使用lambda匿名函数
print(list(map(lambda x: x**2, [1,2,3])))
print(list(map(lambda x,y: x+y, [1,3,5], [2,4,6])))
>>>[1, 4, 9]
>>>[3, 7, 11]
reduce()
说完map(),不得不说一下reduce();只针对python2,在python3中,移除了reduce(),并把它放在了functools模块里,用的时候只需要from functools import reduce
即可
- reduce() 函数会对参数序列中元素进行累积。
- reduce() 函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
def add(x, y) : # 两数相加
return x + y
reduce(add, [1,2,3,4,5]) # 计算列表和:1+2+3+4+5
>>> 15
reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数
>>> 15
reduce(add, [1,2,3,4,5],100) # 可接受第三个参数作为初始值