亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Python秒算24點(diǎn)實(shí)現(xiàn)及原理詳解

系統(tǒng) 1750 0

什么是24點(diǎn)

我們先來約定下老王和他媳婦玩的24點(diǎn)規(guī)則:給定4個任意數(shù)字(0-9),然后通過+,-,*,/,將這4個數(shù)字計(jì)算出24。

小時候玩的都是這個規(guī)則,長大了才有根號,才有各種莫名其妙的高級算法,不好玩了,因?yàn)槲也粫?

可能有人會覺得很簡單,但是真的簡單嗎?

比如:

8,3,3,3
7,3,3,3
你能一眼看出來答案嗎?好像真的可以……

大致思路

這樣想,將四個數(shù)字進(jìn)行全排列,在他們之間添加運(yùn)算符號。

運(yùn)算符我們需要進(jìn)行排列組合,因?yàn)橹挥兴膫€數(shù)字,所以只需要三個運(yùn)算符,而且算法符可能會重復(fù),比如三個都是+。

再遍歷四個數(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 第一個參數(shù)是接收一個課迭代的對象,第二個參數(shù)指定每次排列時從課迭代對象中選著幾個字符進(jìn)行排列。也可以不傳入第二個參數(shù),那么默認(rèn)就是可迭代對象的長度。并且返回一個生成器。

所以我們需要對所有數(shù)字進(jìn)行全排列,就可以像下面這樣寫:

            
def get_all_data_sequence(data_iter):
 return permutations(data_iter)
          

2、然后我們需要拿到所有的操作運(yùn)算符的所有組合方式。這里我們就會使用 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ù)。返回的是一個生成器。

那么獲取所有的操作運(yùn)算符就可以通過這個函數(shù)來獲取了

            
def get_all_operations_sequence():
 operations = ['+','-','*','/']
 return product(operations,repeat=3)
          

3、現(xiàn)在我們已經(jīng)拿到了所有可能組合的操作符和數(shù)字了,接下來就需要對他們進(jìn)行拼接了。然后執(zhí)行運(yùn)算。

這一步操作我們會用到 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 是以最長的一個序列為基準(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() 中,它就能將里面的值依次拿出來。

了解了這兩個函數(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ù),接受一個字符串,能讓這個字符串當(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ù)來幫助我們判斷兩個數(shù)字是否相等了,這個函數(shù)就有一個精度范圍。這樣出現(xiàn)上面情況的時候,我們也能匹配得到條件了。

我們運(yùn)行代碼,然后測試代碼是否能達(dá)到我們的需求。

首先我們測試1,2,3,4四個數(shù)字,

程序出來了結(jié)果 1*2*3*4 24

看來好像我們寫的代碼是正確的

我們再來測試一組數(shù)據(jù)8,8,3,3.

嗯?我們并沒有得到結(jié)果?這四個數(shù)字不能運(yùn)算出24嗎?

8 / ( 3 - 8 / 3 ) 這樣組合可以吧,為什么沒有算出來這種結(jié)果呢?

這是因?yàn)槲覀儧]有考慮括號的原因。括號是可以改變運(yùn)算優(yōu)先級的。所以我們得把括號考慮進(jìn)去。

那么想一下括號最多可以有幾個呢?怎樣給我們的表達(dá)式添加括號呢?

在4個數(shù)字的運(yùn)算中,括號最多只能有三個。

并且,在這里,我們使用一種簡單的方法添加括號,我們把所有可能出現(xiàn)括號的情況全部羅列出來,然后在將得到的運(yùn)算表達(dá)式拼接進(jìn)去。

可能大家會覺得羅列出所有括號出現(xiàn)的情況不現(xiàn)實(shí),因?yàn)橛泻芏嗲闆r

其實(shí)不然,當(dāng)我們?nèi)チ_列的時候,你就會發(fā)現(xiàn),只有11種情況。

            
FORM_STRS = [
 # 數(shù)字 運(yùn)算符 數(shù)字 運(yùn)算符 數(shù)字 運(yùn)算符 數(shù)字
 # 一個括號 的情況
 '(%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)',
 # 兩個括號 的情況
 '(%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))',
 # 三個括號是重復(fù)的,就不用羅列出來了
]
          

然后我們對得到的表達(dá)式在進(jìn)行遍歷拼接,然后我們再運(yùn)算表達(dá)式。

這樣我們就能得出正確的結(jié)果了

代碼寫完了,終于可以開始和媳婦,哦不,老王家的媳婦玩起來了

代碼已全部上傳至Github

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 精品久久久久久午夜 | 高清不卡毛片免费观看 | 日日操狠狠操 | 国产尤物福利视频在线观看 | 伊人网综合视频 | 日韩视频在线一区 | 男女一级做片a性视频 | 在线观看国产一区亚洲bd | 小视频在线免费观看 | 视频1区 | 伊人久久视频 | 夜色福利久久久久久777777 | 国产福利在线观看永久免费 | 久久99精品久久久久久久不卡 | 色偷偷资源网 | 色老头福影院韩国激情影院 | 久久香蕉国产线看观看网站 | 国内精品视频九九九九 | 色香欲综合成人免费视频 | 色综合图区 | 88国产经典欧美一区二区三区 | 欧美一级毛片欧美一级 | 日日噜噜夜夜狠狠视频无 | 精品欧美一区二区三区四区 | 99爱视频99爱在线观看免费 | 国产极品白嫩美女在线观看看 | 久久99蜜桃精品久久久久小说 | 日韩精品一区二区三区高清 | 福利岛国深夜在线 | 中文字幕综合网 | 添bbb免费观看高清视频 | 欧美伦禁片在线播放 | 亚洲视频免费观看 | 5g影院天天爽 | 日韩国产在线 | 夜色伊人| 国产欧美视频在线观看 | 国产人成精品综合欧美成人 | 老司机精品在线播放 | 精品久久久久国产免费 | 青草青青在线视频 |