LeetCode: https://leetcode.com/problems/coin-change/description/
暴力搜索
考虑当前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)
这次记忆化搜索都超时了诶。。。
动态规划
状态转移方程式:
d
p
[
i
]
[
j
]
=
m
i
n
t
∈
[
0
,
1
+
j
/
c
o
i
n
s
]
{
t
+
d
p
[
i
−
1
]
[
j
−
c
o
i
n
s
[
i
]
∗
t
]
}
dp[i][j]=min_{t\in[0,1+j/coins]}\{t+dp[i-1][j-coins[i]*t]\}
dp[i][j]=mint∈[0,1+j/coins]{t+dp[i−1][j−coins[i]∗t]}
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]
依然超时呢。还有什么优化空间吗?
我把递推公式展开来写,你就会发现所谓的优化空间了;
d
p
[
i
]
[
j
]
=
m
i
n
{
d
p
[
i
−
1
]
[
j
]
,
1
+
d
p
[
i
−
1
]
[
j
−
x
]
,
2
+
d
p
[
i
−
1
]
[
j
−
2
x
]
+
.
.
.
}
dp[i][j] = min\{dp[i-1][j],1+dp[i-1][j-x],2+dp[i-1][j-2x]+...\}
dp[i][j]=min{dp[i−1][j],1+dp[i−1][j−x],2+dp[i−1][j−2x]+...}
d
p
[
i
]
[
j
−
x
]
=
m
i
n
{
d
p
[
i
−
1
]
[
j
−
x
]
,
1
+
d
p
[
i
−
1
]
[
j
−
2
x
]
,
2
+
d
p
[
i
−
1
]
[
j
−
3
x
]
+
.
.
.
}
dp[i][j-x] =min\{dp[i-1][j-x],1+dp[i-1][j-2x],2+dp[i-1][j-3x]+...\}
dp[i][j−x]=min{dp[i−1][j−x],1+dp[i−1][j−2x],2+dp[i−1][j−3x]+...}
所以:
d
p
[
i
]
[
j
]
=
m
i
n
{
d
p
[
i
−
1
]
[
j
]
,
1
+
d
p
[
i
]
[
j
−
x
]
}
dp[i][j] = min\{dp[i-1][j],1+dp[i][j-x]\}
dp[i][j]=min{dp[i−1][j],1+dp[i][j−x]}
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]