Python零錢兌換的實(shí)現(xiàn)代碼
題目:
給你一個(gè)整數(shù)數(shù)組 coins ,表示不同面額的硬幣;以及一個(gè)整數(shù) amount ,表示總金額。
計(jì)算并返回可以湊成總金額所需的 最少的硬幣個(gè)數(shù) 。如果沒有任何一種硬幣組合能組成總金額,返回 -1 。你可以認(rèn)為每種硬幣的數(shù)量是無限的。
示例 1:
輸入:coins =
[1, 2, 5], amount =11輸出:
3解釋說明:11 = 5 + 5 + 1
示例 2:
輸入:coins =
[2], amount =3輸出:-1
解釋說明:硬幣無法湊成金額-1
示例 3:
輸入:coins = [1], amount = 0
輸出:0
題目分析:
題目要求用最少的硬幣個(gè)數(shù)湊出總金額amount。我們第一感覺可能是使用暴力或者遞歸解題,對(duì)這道題使用暴力解題,計(jì)算出所有可能的結(jié)果后取硬幣數(shù)最小值,時(shí)間復(fù)雜度妥妥O(n^3),算是很慢的解題方式了,下面我們介紹遞歸解法和玄學(xué)位運(yùn)算解法(使用到位運(yùn)算解法的解題效率一半很高,但是很難想到,所以我愿稱之為“玄學(xué)”)
解題思路:
解法一:遞歸
使用動(dòng)態(tài)規(guī)劃五部曲
1.分析確定dp數(shù)組以及其下標(biāo)的含義或狀態(tài)分析
我們規(guī)定dp[i]表示湊足總額為 i 所需錢幣的最少個(gè)數(shù)。
2.確定遞推公式
我們考慮dp[i]的來源,因?yàn)閐p[i]的來源為dp[i - coins[i]] + 1,(coins[i]表示coins中的第i枚硬幣),這也是dp[i]的唯一來源。
那為什么要+1呢?
這里我們明確dp[i - coins[i]]是湊夠金額 i - coin[i]的最少硬幣個(gè)數(shù)。那么當(dāng)金額i - coin[i]變到 i 時(shí),意味著我們?cè)赾oins中拿了一枚硬幣coins[i],那么從dp[i - coin[i]] 到 dp[i]需要加上所取得那枚硬幣,即+1.
分析到dp[i]狀態(tài)及前面得狀態(tài),dp[i]即為最優(yōu)解。
---------------------------------------
如
coins = [1, 2, 3] amount = 5
那么在 1+1+1+1+1 = 5, 1+2+1+1 = 5, 2+2+1 = 5....等情況中
dp[5]最優(yōu)解必為2+2+1 = 5
即dp[5] = dp[5 - coins[0]] + 1
而dp[5 - coins[0]] = dp[4] = dp[4 - coins[1]] + 1
以此類推
------------------------------------------
我們要取最優(yōu)解(硬幣數(shù)最少)也就是取dp[i - coins[i]] + 1最小值
即遞推公式為:dp[i] = min(dp[i - coins[i]] + 1, dp[i])
(括號(hào)中得dp[i]為上一狀態(tài)的dp[i])
3.如何初始化dp數(shù)組
我們分析公式的基礎(chǔ),可得公式基礎(chǔ)為dp[0]即湊足總額為 0 所需錢幣的最少個(gè)數(shù)。接著考慮到其他dp列表其他下標(biāo)的初始化,由于遞推公式使用了min(),那么為了不讓初始化影響遞推結(jié)果,我們需要將dp[i](i != 0)初始化為一個(gè)很大的數(shù),如正無窮‘inf’。
4.確定遍歷的順序
題目要求的是找到最小硬幣個(gè)數(shù),所以遍歷coins或者先遍歷尋找amount列表無關(guān)緊要。
5.舉例驗(yàn)證推導(dǎo)的dp數(shù)組(公式)是否正確
可以帶入一個(gè)簡單以的例子,比如例1.
代碼實(shí)現(xiàn)
def coinChange(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1代碼注釋
def coinChange(coins, amount):
# 初始化dp列表
dp = [float('inf')] * (amount + 1)
dp[0] = 0 # 初始化遞推公式基礎(chǔ)
for coin in coins: # 遍歷硬幣
# 遍歷尋找構(gòu)成amount最優(yōu)解
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1)
# 如果最終沒有找到湊成amount金額的硬幣,返回-1
return dp[amount] if dp[amount] != float('inf') else -1時(shí)間復(fù)雜度O(nm),n為amoun面額,m為硬幣種數(shù)??臻g復(fù)雜度為O(m),即為dp列表所用空間。
解法二:
接下來就是玄學(xué)位運(yùn)算了。先看代碼
代碼實(shí)現(xiàn)
def coinChange(coins, amount):
if not amount:
return 0
dp = 1 << amount
res = 0
while dp:
tmp = 0
res += 1
for i in coins:
tmp |= dp >> i
if tmp & 1:
return res
dp = tmp
return -1代碼注釋
def coinChange(coins, amount):
if not amount:
return 0
# 按位左移運(yùn)算構(gòu)造類似dp數(shù)組的記錄二進(jìn)制
dp = 1 << amount
res = 0
while dp: # dp = 0或return 時(shí)循環(huán)結(jié)束
tmp = 0 # tmp用于臨時(shí)記錄和承接上一個(gè)dp二進(jìn)制
res += 1 # res為最終答案
for i in coins:
# 利用按位右移不斷右移。利用按位或運(yùn)算
# 將前一次按位右移運(yùn)算與后一次按位右移運(yùn)算合并
tmp |= dp >> i
if tmp & 1: # 當(dāng)tmp最后位數(shù)為1時(shí)res即為答案,返回res
return res
dp = tmp
return -1位運(yùn)算解法過程我打印出來了,不清楚的可以看看
def coinChange(coins, amount):
if not amount:
return 0
dp = 1 << amount
res = 0
while dp:
print('dp:', bin(dp))
tmp = 0
print('tmp:', bin(tmp))
res += 1
print('res:', res)
for i in coins:
print('i:', i)
tmp |= dp >> i
print('ys_tmp:', bin(tmp))
print('--------------')
if tmp & 1:
return res
dp = tmp
return -1輸出
dp: 0b100000000000
tmp: 0b0
res: 1
i: 1
ys_tmp: 0b10000000000
--------------
i: 2
ys_tmp: 0b11000000000
--------------
i: 5
ys_tmp: 0b11001000000
--------------
dp: 0b11001000000
tmp: 0b0
res: 2
i: 1
ys_tmp: 0b1100100000
--------------
i: 2
ys_tmp: 0b1110110000
--------------
i: 5
ys_tmp: 0b1110110010
--------------
dp: 0b1110110010
tmp: 0b0
res: 3
i: 1
ys_tmp: 0b111011001
--------------
i: 2
ys_tmp: 0b111111101
--------------
i: 5
ys_tmp: 0b111111101
--------------
雖然難理解,但是解題效率不是一般的高

時(shí)間復(fù)雜度O(n),n為coins長度??臻g復(fù)雜度O(1),使用有限變量。
到此這篇關(guān)于Python零錢兌換的實(shí)現(xiàn)代碼的文章就介紹到這了,更多相關(guān)Python零錢兌換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用scrapy抓取網(wǎng)站sitemap信息的方法
這篇文章主要介紹了Python使用scrapy抓取網(wǎng)站sitemap信息的方法,涉及Python框架scrapy的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04
Python實(shí)現(xiàn)MySql數(shù)據(jù)庫交互的示例
本文主要介紹了Python實(shí)現(xiàn)MySql數(shù)據(jù)庫交互的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
Python內(nèi)置函數(shù)zip map filter的使用詳解
這篇文章主要介紹了Python內(nèi)置函數(shù)zip map filter的使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
Streamlit+Echarts實(shí)現(xiàn)繪制精美圖表
在數(shù)據(jù)分析和可視化的領(lǐng)域,選擇合適的工具可以讓我們事半功倍,本文主要為大家介紹兩個(gè)工具,Streamlit和ECharts,感興趣的小伙伴可以跟隨小編一起了解下2023-09-09
python進(jìn)程和線程用法知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理了關(guān)于python進(jìn)程和線程用法以及相關(guān)實(shí)例內(nèi)容,需要的朋友們跟著學(xué)習(xí)下。2019-05-05
如何使用scrapy中的ItemLoader提取數(shù)據(jù)
這篇文章主要介紹了如何使用scrapy中的ItemLoader提取數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Python 實(shí)現(xiàn)圖片色彩轉(zhuǎn)換案例
我們?cè)诳磩?dòng)漫、影視作品中,當(dāng)人物在回憶過程中,體現(xiàn)出來的畫面一般都是黑白或者褐色的。本文將提供將圖片色彩轉(zhuǎn)為黑白或者褐色風(fēng)格的案例詳解,感興趣的小伙伴可以了解一下。2021-11-11

