網站首頁 編程語言 正文
題目:
給你一個整數數組 coins ,表示不同面額的硬幣;以及一個整數 amount ,表示總金額。
計算并返回可以湊成總金額所需的 最少的硬幣個數 。如果沒有任何一種硬幣組合能組成總金額,返回 -1 。你可以認為每種硬幣的數量是無限的。
示例 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
題目分析:
題目要求用最少的硬幣個數湊出總金額amount。我們第一感覺可能是使用暴力或者遞歸解題,對這道題使用暴力解題,計算出所有可能的結果后取硬幣數最小值,時間復雜度妥妥O(n^3),算是很慢的解題方式了,下面我們介紹遞歸解法和玄學位運算解法(使用到位運算解法的解題效率一半很高,但是很難想到,所以我愿稱之為“玄學”)
解題思路:
解法一:遞歸
使用動態規劃五部曲
1.分析確定dp數組以及其下標的含義或狀態分析
我們規定dp[i]表示湊足總額為? i? 所需錢幣的最少個數。
2.確定遞推公式?
我們考慮dp[i]的來源,因為dp[i]的來源為dp[i - coins[i]] + 1,(coins[i]表示coins中的第i枚硬幣),這也是dp[i]的唯一來源。
那為什么要+1呢?
這里我們明確dp[i - coins[i]]是湊夠金額 i - coin[i]的最少硬幣個數。那么當金額i - coin[i]變到 i 時,意味著我們在coins中拿了一枚硬幣coins[i],那么從dp[i - coin[i]] 到 dp[i]需要加上所取得那枚硬幣,即+1.
分析到dp[i]狀態及前面得狀態,dp[i]即為最優解。
---------------------------------------
如
coins = [1, 2, 3]? ?amount = 5
那么在 1+1+1+1+1 = 5, 1+2+1+1 = 5, 2+2+1 = 5....等情況中
dp[5]最優解必為2+2+1 = 5
即dp[5] = dp[5 - coins[0]] + 1?
而dp[5 - coins[0]] = dp[4] = dp[4 - coins[1]] + 1
以此類推
------------------------------------------
我們要取最優解(硬幣數最少)也就是取dp[i - coins[i]] + 1最小值
即遞推公式為:dp[i] = min(dp[i - coins[i]] + 1, dp[i])
(括號中得dp[i]為上一狀態的dp[i])
3.如何初始化dp數組
我們分析公式的基礎,可得公式基礎為dp[0]即湊足總額為? 0? 所需錢幣的最少個數。接著考慮到其他dp列表其他下標的初始化,由于遞推公式使用了min(),那么為了不讓初始化影響遞推結果,我們需要將dp[i](i != 0)初始化為一個很大的數,如正無窮‘inf’。
4.確定遍歷的順序
題目要求的是找到最小硬幣個數,所以遍歷coins或者先遍歷尋找amount列表無關緊要。
5.舉例驗證推導的dp數組(公式)是否正確
可以帶入一個簡單以的例子,比如例1.
代碼實現
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 # 初始化遞推公式基礎 for coin in coins: # 遍歷硬幣 # 遍歷尋找構成amount最優解 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
時間復雜度O(nm),n為amoun面額,m為硬幣種數。空間復雜度為O(m),即為dp列表所用空間。
解法二:
接下來就是玄學位運算了。先看代碼
代碼實現
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 # 按位左移運算構造類似dp數組的記錄二進制 dp = 1 << amount res = 0 while dp: # dp = 0或return 時循環結束 tmp = 0 # tmp用于臨時記錄和承接上一個dp二進制 res += 1 # res為最終答案 for i in coins: # 利用按位右移不斷右移。利用按位或運算 # 將前一次按位右移運算與后一次按位右移運算合并 tmp |= dp >> i if tmp & 1: # 當tmp最后位數為1時res即為答案,返回res return res dp = tmp return -1
位運算解法過程我打印出來了,不清楚的可以看看
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
--------------
雖然難理解,但是解題效率不是一般的高
時間復雜度O(n),n為coins長度。空間復雜度O(1),使用有限變量。
原文鏈接:https://blog.csdn.net/m0_61791601/article/details/124654483
相關推薦
- 2022-05-06 input 限制輸入 小數點后兩位
- 2022-10-11 TCP/IP協議類比生活案例
- 2022-07-23 SpringBoot分頁查詢
- 2022-08-28 本周遇到的一些問題整理,有些未完全解決,留在下周寫
- 2022-07-24 用來將對象持久化的python?pickle模塊_python
- 2022-01-09 el-tree同級節點可選擇 其他節點及父節點禁用
- 2022-09-08 Redis?Lua腳本實現ip限流示例_Redis
- 2022-12-15 C#利用KPM算法解決字符串匹配問題詳解_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支