由买买提看人间百态

boards

本页内容为未名空间相应帖子的节选和存档,一周内的贴子最多显示50字,超过一周显示500字 访问原贴
JobHunting版 - 大师看看我的Change-making新算法是不是首创,最优
相关主题
请教下3sum为撒超时C++ Q23: if if else
求助各位大牛:LeetCode的Decode Ways我这个 3Sum 怎么过不了leetcode的测试阿
Find Median Of Two Sorted Arraysleetcode 关于Partition List
lc新题,贴个刚写的solutionleetcode我这2个palindrome的为什么过不了大oj
n queens II ,, 時間复杂度是多少?thank贴个coin exchange问题的O(1)时间复杂度的解法
大牛看看为撒这个sqrt binary search过不了OJ求助:3sum总是运行不过
Combination Sum 时间和空间复杂度是多少?lc 上面4 sum的时间复杂度要求多少?
找零钱dp的问题我这个 4sum的解法是 o^3还是o^2? , xiexie
相关话题的讨论汇总
话题: coins话题: amount话题: imax话题: gcd话题: return
进入JobHunting版参与讨论
1 (共1页)
J*****4
发帖数: 1
1
https://en.wikipedia.org/wiki/Change-making_problem
leetcode 322题
我的算法python源码
‘’‘
import math
import time
'''old way dp to amount'''
class Solution_old:
def coinChange(self, coins, amount: int) -> int:
dp = [math.inf] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for c in coins:
if c <= i:
dp[i] = min(dp[i], dp[i - c] + 1)
if dp[amount] == math.inf:
return -1
else:
return dp[amount]
def get_gcd(a, b):
if a >= b:
n1 = a
n2 = b
else:
n1 = b
n2 = a
while True:
m = n1 % n2
if m == 0:
return n2
else:
n1 = n2
n2 = m
'''new way , do not always dp to amount'''
class Solution_new:
def coinChange(self, coins, amount: int) -> int:
if amount == 0:
return 0
if len(coins) == 0 :
return -1
if len(coins)==1:
if amount % coins[0] !=0:
return -1
else:
return amount//coins[0]
gcd = coins[0]
for i in range(1,len(coins)):
gcd = get_gcd(gcd, coins[i])
if (amount % gcd) != 0:
return -1
else:
amount=amount // gcd
imax=coins[0]//gcd
imin=imax
for i in range(len(coins)):
coins[i]=coins[i]//gcd
if coins[i]>imax:
imax=coins[i]
if coins[i] imin=coins[i]
if amount < imin:
return -1
cnt = 0
i = imin
table = [math.inf]*imin
table[0]=0
while cnt < imax:
min_n =math.inf
for c in coins:
if c <= i:
min_n = min(min_n, table[i - c] + 1)
table.append(min_n)
if i>=imax:
min_pre=table[i - imax]
else:
min_pre=math.inf
if min_n - min_pre != 1:
cnt = 0
else:
cnt += 1
if amount == i:
if min_n == math.inf:
return -1
else:
return min_n
i += 1
start = i - imax-1
m = amount // imax
v_mod = amount % imax
i = start // imax
i_mod = start % imax
if v_mod < i_mod:
i = i + 1
index = v_mod + i * imax
ret = (m - i + table[index])
if ret == math.inf:
return -1
else:
return ret
if __name__=="__main__":
#run time compare
s = Solution_old()
coins = [186, 419, 83, 408]
a = time.time()
print(s.coinChange(coins, 1000000))
print(time.time() - a)
s=Solution_new()
coins=[186,419,83,408]
a=time.time()
print(s.coinChange(coins, 1000000))
print(time.time()-a)
""" result on my computer
2388
1.5335829257965088
2388
0.0724637508392334
"""
’‘’
J*****4
发帖数: 1
2
就是给定一组面值不一样的硬币,再给定一个目标数字N,求组成这个数字的最少的硬
币数量。我目前看到的最优时间复杂度都是随N线性增长的。我这个算法时间复杂度并
不随N线性增加,更加优化。各位怎么看?
J*****4
发帖数: 1
3
奇怪,怎么没人给点想法或意见。究竟算不算一个更好的算法?
J*****4
发帖数: 1
4
我的这个算法时间复杂度不会超过最大的两个coin值的乘积。
比如coins=[1,2,5] 则时间复杂度不会超过10, 无论amount是多少
比如coins=[1,2,5,9] 则时间复杂度不会超过45, 无论amount是多少
直觉如此,未严格证明,大家看我这个算法对吗?
E**********e
发帖数: 1736
5
先顶在下载。

【在 J*****4 的大作中提到】
: 我的这个算法时间复杂度不会超过最大的两个coin值的乘积。
: 比如coins=[1,2,5] 则时间复杂度不会超过10, 无论amount是多少
: 比如coins=[1,2,5,9] 则时间复杂度不会超过45, 无论amount是多少
: 直觉如此,未严格证明,大家看我这个算法对吗?

J*****4
发帖数: 1
6
终于有人感兴趣研究下了,感谢感谢


: 先顶在下载。



【在 E**********e 的大作中提到】
: 先顶在下载。
J*****4
发帖数: 1
7
https://en.wikipedia.org/wiki/Change-making_problem
leetcode 322题
我的算法python源码
‘’‘
import math
import time
'''old way dp to amount'''
class Solution_old:
def coinChange(self, coins, amount: int) -> int:
dp = [math.inf] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for c in coins:
if c <= i:
dp[i] = min(dp[i], dp[i - c] + 1)
if dp[amount] == math.inf:
return -1
else:
return dp[amount]
def get_gcd(a, b):
if a >= b:
n1 = a
n2 = b
else:
n1 = b
n2 = a
while True:
m = n1 % n2
if m == 0:
return n2
else:
n1 = n2
n2 = m
'''new way , do not always dp to amount'''
class Solution_new:
def coinChange(self, coins, amount: int) -> int:
if amount == 0:
return 0
if len(coins) == 0 :
return -1
if len(coins)==1:
if amount % coins[0] !=0:
return -1
else:
return amount//coins[0]
gcd = coins[0]
for i in range(1,len(coins)):
gcd = get_gcd(gcd, coins[i])
if (amount % gcd) != 0:
return -1
else:
amount=amount // gcd
imax=coins[0]//gcd
imin=imax
for i in range(len(coins)):
coins[i]=coins[i]//gcd
if coins[i]>imax:
imax=coins[i]
if coins[i] imin=coins[i]
if amount < imin:
return -1
cnt = 0
i = imin
table = [math.inf]*imin
table[0]=0
while cnt < imax:
min_n =math.inf
for c in coins:
if c <= i:
min_n = min(min_n, table[i - c] + 1)
table.append(min_n)
if i>=imax:
min_pre=table[i - imax]
else:
min_pre=math.inf
if min_n - min_pre != 1:
cnt = 0
else:
cnt += 1
if amount == i:
if min_n == math.inf:
return -1
else:
return min_n
i += 1
start = i - imax-1
m = amount // imax
v_mod = amount % imax
i = start // imax
i_mod = start % imax
if v_mod < i_mod:
i = i + 1
index = v_mod + i * imax
ret = (m - i + table[index])
if ret == math.inf:
return -1
else:
return ret
if __name__=="__main__":
#run time compare
s = Solution_old()
coins = [186, 419, 83, 408]
a = time.time()
print(s.coinChange(coins, 1000000))
print(time.time() - a)
s=Solution_new()
coins=[186,419,83,408]
a=time.time()
print(s.coinChange(coins, 1000000))
print(time.time()-a)
""" result on my computer
2388
1.5335829257965088
2388
0.0724637508392334
"""
’‘’
J*****4
发帖数: 1
8
就是给定一组面值不一样的硬币,再给定一个目标数字N,求组成这个数字的最少的硬
币数量。我目前看到的最优时间复杂度都是随N线性增长的。我这个算法时间复杂度并
不随N线性增加,更加优化。各位怎么看?
J*****4
发帖数: 1
9
奇怪,怎么没人给点想法或意见。究竟算不算一个更好的算法?
J*****4
发帖数: 1
10
我的这个算法时间复杂度不会超过最大的两个coin值的乘积。
比如coins=[1,2,5] 则时间复杂度不会超过10, 无论amount是多少
比如coins=[1,2,5,9] 则时间复杂度不会超过45, 无论amount是多少
直觉如此,未严格证明,大家看我这个算法对吗?
E**********e
发帖数: 1736
11
先顶在下载。

【在 J*****4 的大作中提到】
: 我的这个算法时间复杂度不会超过最大的两个coin值的乘积。
: 比如coins=[1,2,5] 则时间复杂度不会超过10, 无论amount是多少
: 比如coins=[1,2,5,9] 则时间复杂度不会超过45, 无论amount是多少
: 直觉如此,未严格证明,大家看我这个算法对吗?

J*****4
发帖数: 1
12
终于有人感兴趣研究下了,感谢感谢


: 先顶在下载。



【在 E**********e 的大作中提到】
: 先顶在下载。
J*****4
发帖数: 1
13
再说详细点:
问题描述:
给你几个不同面值的硬币coins和一个总钱数 amount,求组成amount的最少硬币数量,
如果没有解,则返回-1
Examples:
Input : coins = [1, 2, 5], amount = 11
最少组成是两个5和一个1,所以
Output :3
Input :coins = [ 2, 5], amount = 8
无解
Output : -1
1:传统解法
假设 F(n) 是对于amount = n 的答案, 硬币数量是s.
则F(n) = min( F(n -coin[0])+1,F(n -coin[1])+1,...,F(n-coin[s-1])+1)
我们 从 F(0)开始用动态规划算法得到 F(n).
[sourcecode language="Python3" highlight=""]
def coinChange(coins: List[int], amount: int) -> int:
dp=[math.inf]*(amount+1)
dp[0] = 0
for i in range(1,amount+1):
for c in coins:
if c <= i:
dp[i] = min(dp[i], dp[i - c] + 1)

if dp[amount]==math.inf:
return -1
else:
return dp[amount]
[/sourcecode]
时间复杂度 : O(s*n) s是硬币数量, n是amount的值
2: 因为如下的两个输入的答案是一样的 :coins = [ 2, 5], amount = 101 和输入 :
coins = [ 4, 10], amount = 202. 所以先用最大公约数gcd可以减少时间复杂度到 O(
s*n/gcd) .
[sourcecode language="Python3" highlight=""]
import math
def get_gcd(a, b):
if a >= b:
n1 = a
n2 = b
else:
n1 = b
n2 = a
while True:
m = n1 % n2
if m == 0:
return n2
else:
n1 = n2
n2 = m
def coinChange(coins, n):
# some corn cases
if n == 0:
return 0
if len(coins) == 0:
return -1
if len(coins) == 1:
if n % coins[0] != 0:
return -1
else:
return n // coins[0]
gcd = coins[0]
for i in range(1, len(coins)):
gcd = get_gcd(gcd, coins[i])
if (n % gcd) != 0:
return -1
else:
n = n // gcd
imax = coins[0] // gcd
imin = imax
for i in range(len(coins)):
coins[i] = coins[i] // gcd
if coins[i] > imax:
imax = coins[i]
if coins[i] < imin:
imin = coins[i]
if n < imin:
return -1
mins = [math.inf] * (n + 1)
mins[0] = 0
for i in range(1,n+1):
for c in coins:
if c <= i:
mins[i]=min(mins[i],mins[i-c]+1)
if mins[-1] == math.inf:
return -1
else:
return mins[-1]
[/sourcecode]
3: 新算法. 如果coins 的 gcd =1(if gcd 不等于1,我们可以简化为1) , 假设amount=
n 的答案 F(n). 必然存在一个数字m , 对于每一个大于m的数i, F(i)=F(i-maxcoin)
+1. 所以如果 n > m , 我们可以通过计算得到 F(n) .
时间复杂度 : min(O(s*n), O(s*m)) ,m 数值应该是两个最大的币值乘值同一个级别。
Examples:
Input :coins = [ 2, 5]
F(0) : 0
....
....
F(8) : -1
F(9) : 3
F(10) : 2
F(11) : 4
F(12) : 3
F(13) : 5
F(14) : 4 = F(14-5) +1 //从n=14后就满足F(i)=F(i-maxcoin) +1
F(15) : 3 = F(15-5) +1
...
对于输入 coins =[2,5] ,n . 因为 m = 14. 所以不管 n 是多大,时间复杂度不会超
过 s*m = 2 *(14+5) =38.
[sourcecode language="Python3" highlight=""]
import math
def get_gcd(a, b):
if a >= b:
n1 = a
n2 = b
else:
n1 = b
n2 = a
while True:
m = n1 % n2
if m == 0:
return n2
else:
n1 = n2
n2 = m
def coinChange(coins, n):
if n == 0:
return 0
if len(coins) == 0:
return -1
if len(coins) == 1:
if n % coins[0] != 0:
return -1
else:
return n // coins[0]
gcd = coins[0]
for i in range(1, len(coins)):
gcd = get_gcd(gcd, coins[i])
if (n % gcd) != 0:
return -1
else:
n = n // gcd
imax = coins[0] // gcd
imin = imax
for i in range(len(coins)):
coins[i] = coins[i] // gcd
if coins[i] > imax:
imax = coins[i]
if coins[i] < imin:
imin = coins[i]
if n < imin:
return -1
cnt = 0
i = imin
table = [math.inf] * (n + 1)
table[0] = 0
while cnt < imax:
for c in coins:
if c <= i:
table[i] = min(table[i], table[i - c] + 1)
if i >= imax:
min_pre = table[i - imax]
else:
min_pre = math.inf
if table[i] - min_pre != 1:
cnt = 0
else:
cnt += 1
if n == i:
if table[i] == math.inf:
return -1
else:
return table[i]
i += 1
start = i - imax - 1
times = (n - start) // imax
index = (n - start) % imax + start
return (times + table[index])
[/sourcecode]
1 (共1页)
进入JobHunting版参与讨论
相关主题
这种backtracking的问题怎么算时间复杂度?比如palindrom patitioning.n queens II ,, 時間复杂度是多少?thank
约瑟夫问题 用循环链表算法 时间 复杂度多少大牛看看为撒这个sqrt binary search过不了OJ
请教一道面试题Combination Sum 时间和空间复杂度是多少?
乘方函数还有简解么找零钱dp的问题
请教下3sum为撒超时C++ Q23: if if else
求助各位大牛:LeetCode的Decode Ways我这个 3Sum 怎么过不了leetcode的测试阿
Find Median Of Two Sorted Arraysleetcode 关于Partition List
lc新题,贴个刚写的solutionleetcode我这2个palindrome的为什么过不了大oj
相关话题的讨论汇总
话题: coins话题: amount话题: imax话题: gcd话题: return