面试题 08.11. 硬币(C++)

题目详情

硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

示例1:
输入: n = 5
输出:2
解释: 有两种方式可以凑成总金额:
5=5
5=1+1+1+1+1

示例2:
输入: n = 10
输出:4
解释: 有四种方式可以凑成总金额:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1

说明:
注意:
你可以假设:

  • 0 <= n (总金额) <= 1000000
     

——题目难度:中等

 


 

思路(借鉴)
n25、n10、n5、n1分别代表币值为25、10、5、1分的硬币数
n= 25*n25 + 10*n10 + 5*n5 + 1*n1


1.一开始三层嵌套for循环试试能不能暴力穷举解决,不是四层for循环的原因是因为题目只要求返回有几种表示法,所以n5一旦确认下来,n1的数量也能够确定。第一次结果当然是超时了...

class Solution {
public:
	const int M = 1000000007;
    int waysToChange(int n) { // n= 25*n25 + 10*n10 + 5*n5 + 1*n1
    	int ans = 0;	
		for(int n25=0;n25<=n/25;n25++) //n25、n10、n5分别代表币值为25、10、5分的硬币数 
		{	int temp1 = n - 25*n25;
			for(int n10=0;n10<=temp1/10;n10++)
			{
				int temp2 = temp1 - 10*n10;
				for(int n5=0;n5<=temp2/5;n5++)
				{
					ans++; //5分的硬币数量确定下来了,1分的硬币数量也就确认下来了 
                    ans=ans%M;
				}
			}
		}
   	return ans;
    }
};

第一次结果



2.接着发现n5循环的次数其实和n10的大小有关,所以进一步化简。但最后还是会超时。

class Solution {
public:
	const int M = 1000000007;
    int waysToChange(int n) { // n= 25*n25 + 10*n10 + 5*n5 + 1*n1
    	int ans = 0;
		for(int n25=0;n25<=n/25;n25++)
		{	int temp1 = n - 25*n25;
			for(int n10=0;n10<=temp1/10;n10++)
			{
				ans = ans + (temp1 - 10*n10)/5 + 1;// 每次不同的n10都有( (temp1 - 10*n10)/5 + 1(当n5=0必有一种) )种 
                ans = ans%M;
			}
		}
   	return ans;
    }
};

第二次结果



3.最后其实关于n10的这层for循环也可以被n25来决定,这时可以将第二次尝试中第二层for循环的"ans = ans + (temp1 - 10*n10)/5 + 1"看成是看成等差数列求和这一过程(下面把temp1看成temp)

通项公式an = (temp - n10*10)/5 + 1
项数为 temp/10 + 1 项
首项为 temp/5 + 1
末项为 (temp - temp/10*10)/5 + 11.当temp=10*k(k>=0)时, 末项为0
 

2.当temp=10k(k>=1) - m(m<10),末项为10k-m-10*((10k-m)/10)

例:k=2,m=1时, temp=19,末项为2

所以末项也可以表示为 (temp%10)/5 + 1 


 

 

了解了思路,代码如下
 

class Solution {
public:
	const int M = 1000000007;
    int waysToChange(int n) { // n= 25*n25 + 10*n10 + 5*n5 + 1*n1
    	int ans = 0;
		for(int n25=0;n25<=n/25;n25++)
		{	int temp = n - 25*n25; //等效为等差数列的首项 
			ans=(ans + ( (temp/5 + 1)+(long long)((temp%10)/5 + 1) )*(temp/10+1)/2 )%M;
		}
   	return ans;
    }
};

 结果

 


 

 

 

 
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

重剑DS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值