摘要:周末閑來無事,看到隔壁家的老王在和隔壁家的媳婦玩點(diǎn),就進(jìn)屋看了看。發(fā)現(xiàn)老王是真不行啊,那不行,這也不行。什么是點(diǎn)我們先來約定下老王和他媳婦玩的點(diǎn)規(guī)則給定個(gè)任意數(shù)字,然后通過,將這個(gè)數(shù)字計(jì)算出。
周末閑來無事,看到隔壁家的老王在和隔壁家的媳婦玩24點(diǎn),就進(jìn)屋看了看。發(fā)現(xiàn)老王是真不行啊,那不行,這也不行。
就連個(gè)24點(diǎn)都玩不過他媳婦,給他媳婦氣的,啥都不能滿足,這不能,那也不能。
我坐下來和他媳婦玩了兩把,那都是無出其右,把把贏!
我要走的時(shí)候,他媳婦還挽留我多玩幾把,有意思。
為了能讓老王在他媳婦面前抬起頭來,我決定幫他一把……就用python寫了個(gè)算24點(diǎn)的玩意,老王對我感激涕零。
什么是24點(diǎn)我們先來約定下老王和他媳婦玩的24點(diǎn)規(guī)則:給定4個(gè)任意數(shù)字(0-9),然后通過+,-,*,/,將這4個(gè)數(shù)字計(jì)算出24。
小時(shí)候玩的都是這個(gè)規(guī)則,長大了才有根號(hào),才有各種莫名其妙的高級算法,不好玩了,因?yàn)槲也粫?huì)。
可能有人會(huì)覺得很簡單,但是真的簡單嗎?
比如:
8,3,3,3
7,3,3,3
你能一眼看出來答案嗎?好像真的可以……
大致思路這樣想,將四個(gè)數(shù)字進(jìn)行全排列,在他們之間添加運(yùn)算符號(hào)。
運(yùn)算符我們需要進(jìn)行排列組合,因?yàn)橹挥兴膫€(gè)數(shù)字,所以只需要三個(gè)運(yùn)算符,而且算法符可能會(huì)重復(fù),比如三個(gè)都是+。
再遍歷四個(gè)數(shù)字的全排列,對每一組數(shù)字而言,遍歷所有組合的操作符。最后將數(shù)字和操作符進(jìn)行拼接運(yùn)算,就可以得到最終結(jié)果了。
演示環(huán)境操作系統(tǒng):windows10
python版本:python 3.7
代碼編輯器:pycharm 2018.2
使用模塊:math,itertools, collections.abc
具體代碼1、首先我們對所有數(shù)字進(jìn)行去全排列,這里我們使用 itertools.permutations 來幫助我們完成。
iertools.permutations 用法演示
from itertools import permutations data_list = permutations([1,2,3,4],2) for data in data_list: print(data)
結(jié)果顯示
(1, 2) (1, 3) (1, 4) (2, 1) (2, 3) (2, 4) (3, 1) (3, 2) (3, 4) (4, 1) (4, 2) (4, 3)
permutations 第一個(gè)參數(shù)是接收一個(gè)課迭代的對象,第二個(gè)參數(shù)指定每次排列時(shí)從課迭代對象中選著幾個(gè)字符進(jìn)行排列。也可以不傳入第二個(gè)參數(shù),那么默認(rèn)就是可迭代對象的長度。并且返回一個(gè)生成器。
所以我們需要對所有數(shù)字進(jìn)行全排列,就可以像下面這樣寫:
def get_all_data_sequence(data_iter): return permutations(data_iter)
2、然后我們需要拿到所有的操作運(yùn)算符的所有組合方式。這里我們就會(huì)使用 itertools.product 函數(shù)了。
itertools.product 用法演示
from itertools import product sequence1 = product("ABCD","xy") sequence2 = product([0,1],repeat=3) for sequence in sequence1: print(sequence) print("-"*30) for sequence in sequence2: print(sequence)
結(jié)果顯示
("A","x") ("A","y") ("B","x") ("B","y") ("C","x") ("C","y") ("D","x") ("D","y") ------------------------------ (0, 0, 0) (0, 0, 1) (0, 1, 0) (0, 1, 1) (1, 0, 0) (1, 0, 1) (1, 1, 0) (1, 1, 1)
itertools.product,返回傳入所有序列中笛卡爾積的元祖,repeat參數(shù)表示傳入序列的重復(fù)次數(shù)。返回的是一個(gè)生成器。
那么獲取所有的操作運(yùn)算符就可以通過這個(gè)函數(shù)來獲取了
def get_all_operations_sequence(): operations = ["+","-","*","/"] return product(operations,repeat=3)
3、現(xiàn)在我們已經(jīng)拿到了所有可能組合的操作符和數(shù)字了,接下來就需要對他們進(jìn)行拼接了。然后執(zhí)行運(yùn)算。
這一步操作我們會(huì)用到 itertools.zip_longest() 和 itertools.chain.form_iterable() 函數(shù)。
itertools.zip_longest() 用法演示
data = zip_longest([1,2,3,4],["*","-","+"],fillvalue="") for value in data: print(value)
結(jié)果顯示
(1, "*") (2, "-") (3, "+") (4, "")
zip_longest() 其實(shí)和 python 內(nèi)置的 zip() 函數(shù)用法差不多,只是 zip_longest 是以最長的一個(gè)序列為基準(zhǔn),缺失值就使用 fillvalue 參數(shù)的值進(jìn)行填充
itertools.chain.form_iterable() 用法演示
data = zip_longest([1,2,3,4],["*","-","+"],fillvalue="") data_chain = chain.from_iterable(data) for value in data_chain: print(value)
結(jié)果顯示
1 * 2 - 3 + 4
這里的data是什么樣的大家知道了吧,然后我們將data傳入 chain.form_iterable() 中,它就能將里面的值依次拿出來。
了解了這兩個(gè)函數(shù)之后,那么我們就可以開始拼接數(shù)字和操作運(yùn)算符了。
def calculate(self): """ 計(jì)算值,返回對應(yīng)的表達(dá)式和值 :return: """ for data_sequence in get_all_data_sequence(): operation_sequences = get_all_operation_sequence() for operation_sequence in operation_sequences: value = zip_longest(data_sequence, operation_sequence, fillvalue="") value_chain = chain.from_iterable(value) calculate_str = "" # 對得到的字符進(jìn)行拼接成為表達(dá)式 calculate_str for _ in value_chain: calculate_str += _ try: result = eval(calculate_str # 處理被除數(shù)可能為零的情況,然后就直接跳過這次循環(huán) except ZeroDivisionError: continue if math.isclose(result, 24): return calculate_str,result return None,None代碼分析
1、eval() 函數(shù),接受一個(gè)字符串,能讓這個(gè)字符串當(dāng)成 python 代碼運(yùn)行,返回運(yùn)行的結(jié)果。
2、math.isclose():為什么這里需要使用 math.isclose() ,而不是直接使用==運(yùn)算符呢?這是因?yàn)樽詈笏愠鰜淼谋磉_(dá)式可能有精度問題,例如23.9...或者24.0...等數(shù)字,所以我們就需要使用math.isclose()函數(shù)來幫助我們判斷兩個(gè)數(shù)字是否相等了,這個(gè)函數(shù)就有一個(gè)精度范圍。這樣出現(xiàn)上面情況的時(shí)候,我們也能匹配得到條件了。
我們運(yùn)行代碼,然后測試代碼是否能達(dá)到我們的需求。
首先我們測試1,2,3,4四個(gè)數(shù)字,
程序出來了結(jié)果 1*2*3*4 24
看來好像我們寫的代碼是正確的
我們再來測試一組數(shù)據(jù)8,8,3,3.
嗯?我們并沒有得到結(jié)果?這四個(gè)數(shù)字不能運(yùn)算出24嗎?
8 / ( 3 - 8 / 3 ) 這樣組合可以吧,為什么沒有算出來這種結(jié)果呢?
這是因?yàn)槲覀儧]有考慮括號(hào)的原因。括號(hào)是可以改變運(yùn)算優(yōu)先級的。所以我們得把括號(hào)考慮進(jìn)去。
那么想一下括號(hào)最多可以有幾個(gè)呢?怎樣給我們的表達(dá)式添加括號(hào)呢?
在4個(gè)數(shù)字的運(yùn)算中,括號(hào)最多只能有三個(gè)。
并且,在這里,我們使用一種簡單的方法添加括號(hào),我們把所有可能出現(xiàn)括號(hào)的情況全部羅列出來,然后在將得到的運(yùn)算表達(dá)式拼接進(jìn)去。
可能大家會(huì)覺得羅列出所有括號(hào)出現(xiàn)的情況不現(xiàn)實(shí),因?yàn)橛泻芏嗲闆r
其實(shí)不然,當(dāng)我們?nèi)チ_列的時(shí)候,你就會(huì)發(fā)現(xiàn),只有11種情況。
FORM_STRS = [ # 數(shù)字 運(yùn)算符 數(shù)字 運(yùn)算符 數(shù)字 運(yùn)算符 數(shù)字 # 一個(gè)括號(hào) 的情況 "(%s %s %s) %s %s %s %s", "(%s %s %s %s %s) %s %s", "(%s %s %s %s %s %s %s)", "%s %s (%s %s %s) %s %s", "%s %s (%s %s %s %s %s)", "%s %s %s %s (%s %s %s)", # 兩個(gè)括號(hào) 的情況 "(%s %s %s) %s (%s %s %s)", "( (%s %s %s) %s %s) %s %s", "( %s %s (%s %s %s)) %s %s", "%s %s ((%s %s %s) %s %s)", "%s %s (%s %s (%s %s %s))", # 三個(gè)括號(hào)是重復(fù)的,就不用羅列出來了 ]
然后我們對得到的表達(dá)式在進(jìn)行遍歷拼接,然后我們再運(yùn)算表達(dá)式。
這樣我們就能得出正確的結(jié)果了
代碼寫完了,終于可以開始和媳婦,哦不,老王家的媳婦玩起來了
代碼已全部上傳至Github:https://github.com/MiracleYou...
關(guān)注公眾號(hào)「Python專欄」,更多好玩有趣的Python等著你
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/45256.html
摘要:今天我們來說一個(gè)非常實(shí)用的例子,小菜接到組長老王的一個(gè)任務(wù),安排一個(gè)新的活,這個(gè)活是這樣的老王小菜啊,你幫我寫一個(gè)登入腳本,跑十幾條命令到服務(wù)器上,然后存一下日志。這個(gè)時(shí)候,小菜偷偷的瞄了一眼組長老王,常舒一口氣,總于寫完了。 Python學(xué)了好幾年,發(fā)現(xiàn)功力還是那樣,很多同學(xué)經(jīng)常這樣抱...
摘要:八皇后問題是十九世紀(jì)著名的數(shù)學(xué)家高斯年提出。同時(shí)可以擴(kuò)展為九皇后,十皇后問題。解決方案回溯與遞歸。這樣,編譯器或者解釋器就可以把尾遞歸做優(yōu)化,使遞歸本身無論調(diào)用多少次,都只占用一個(gè)棧幀,不會(huì)出現(xiàn)棧溢出的情況。 八皇后問題是十九世紀(jì)著名的數(shù)學(xué)家高斯1850年提出 。以下為python語言的八皇后代碼,摘自《Python基礎(chǔ)教程》,代碼相對于其他語言,來得短小且一次性可以打印出92種結(jié)果。...
摘要:大學(xué),光學(xué)工程研究生畢業(yè),和程序猿完全不搭邊。那怎么辦,試著學(xué)一學(xué)唄,學(xué)習(xí)才是程序猿的天性。所以我在想程序猿是不是都需要新知識(shí)刺激一下,才能保持興奮的頭腦。有句話說的很對程序猿就像好奇的貓,追著毛球的線頭玩,最后一個(gè)毛球在腦袋里攪漿糊。 說說我自己的經(jīng)歷。211大學(xué),光學(xué)工程研究生畢業(yè),和程序猿完全不搭邊。 畢業(yè)后進(jìn)了成都某國字頭研究所,在行業(yè)里摸爬滾打了四年,2018年機(jī)緣巧合在家養(yǎng)...
摘要:從事件談安全大新聞在剛剛過去的年月日,和的研究人員公開了個(gè)文件,我也第一時(shí)間下載并按提示檢查了的校驗(yàn)值。這個(gè)簡單的事實(shí)轟動(dòng)了安全界,因?yàn)檫@說明世界上首次實(shí)際意義上公開的的碰撞試驗(yàn)取得了成功。 從SHAttered事件談安全 大新聞? 在剛剛過去的2017年2月23日,Cryptology Group at Centrum Wiskunde & Informatica (CWI)和Goo...
閱讀 2435·2021-09-01 10:41
閱讀 1451·2019-08-30 14:12
閱讀 520·2019-08-29 12:32
閱讀 2868·2019-08-29 12:25
閱讀 2943·2019-08-28 18:30
閱讀 1713·2019-08-26 11:47
閱讀 989·2019-08-26 10:35
閱讀 2597·2019-08-23 18:06