再學動態規劃之 完全揹包
阿新 • • 發佈:2018-12-15
暴力搜尋
考慮當前index 拿1張,2張,…時候,從index+1開始的最小張數。相加即可:
import sys
class Solution(object):
def get_small_number(self, coins, index, amount):
if amount == 0:
return 0
if amount < 0:
return -1
if index == len(coins)-1:
if amount%coins[index] != 0 :
return -1
else:
return amount/coins[index]
min_res = sys.maxint
for i in range(amount/coins[index] + 1):
back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
this_amount = back_amount + i
if back_amount == -1:
this_amount = sys.maxint
min_res = min(min_res, this_amount)
return min_res
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
return -1 if self. get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)
記憶化搜尋
當前的問題就是,每次都沒有把結果記錄下來,導致重複計算。故 超時 比如[1 ,2, 5] 目標是 11 的時候。1拿2張,2拿0張 和 1拿0張,2拿1張;應該是一種情況。
import sys
res = dict()
class Solution(object):
def get_small_number(self, coins, index, amount):
if amount == 0:
return 0
if amount < 0:
return -1
if index == len(coins)-1:
if amount%coins[index] != 0:
return -1
else:
return amount/coins[index]
if str(index)+'_'+str(amount) in res:
return res[str(index)+'_'+str(amount)]
min_res = sys.maxint
for i in range(amount/coins[index] + 1):
back_amount = self.get_small_number(coins, index+1, amount-i*coins[index])
this_amount = back_amount + i
if back_amount == -1:
this_amount = sys.maxint
min_res = min(min_res, this_amount)
res[str(index)+'_'+str(amount)] = min_res
return min_res
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
res.clear()
return -1 if self.get_small_number(coins, 0, amount) == sys.maxint else self.get_small_number(coins, 0, amount)
這次記憶化搜尋都超時了誒。。。
動態規劃
狀態轉移方程式:
import sys
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
for ix in range(len(coins)+1):
arr[ix][0] = 0
for i in range(1, len(coins)+1):
for j in range(1, amount+1):
res_min = arr[i-1][j]
for t in range(1, j/coins[i-1]+1):
res_min = min(res_min, t+arr[i-1][j-coins[i-1]*t])
arr[i][j] = res_min
return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]
依然超時呢。還有什麼優化空間嗎? 我把遞推公式展開來寫,你就會發現所謂的優化空間了; 所以:
import sys
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
arr = [[sys.maxint for _ in range(amount+1)] for _ in range(len(coins)+1)]
for ix in range(len(coins)+1):
arr[ix][0] = 0
# arr[:][0] = 1
for i in range(1, len(coins)+1):
for j in range(1, amount+1):
res_min = arr[i-1][j]
if j - coins[i-1] >= 0:
res_min = min(res_min, 1+arr[i][j-coins[i-1]])
arr[i][j] = res_min
return -1 if arr[-1][-1] == sys.maxint else arr[-1][-1]