「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。
描述
Hercy 想要为购买第一辆车存钱。他 每天 都往力扣银行里存钱。
最开始,他在周一的时候存入 1 块钱。从周二到周日,他每天都比前一天多存入 1 块钱。在接下来每一个周一,他都会比 前一个周一 多存入 1 块钱。
给你 n ,请你返回在第 n 天结束的时候他在力扣银行总共存了多少块钱。
示例 1:
输入:n = 4
输出:10
解释:第 4 天后,总额为 1 + 2 + 3 + 4 = 10 。
示例 2:
输入:n = 10
输出:37
解释:第 10 天后,总额为 (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4) = 37 。注意到第二个星期一,Hercy 存入 2 块钱。
示例 3:
输入:n = 20
输出:96
解释:第 20 天后,总额为 (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4 + 5 + 6 + 7 + 8) + (3 + 4 + 5 + 6 + 7 + 8) = 96 。
提示:
1 <= n <= 1000
做题
思路:
这道题目是让我们去求递增数列,每周都是一个新的递增数列。
暴力循环法
首先,我们需要一个变量 weeks 来表示这一周是第几周,这一周的其实存储金额是多少。
第二,第一周每天存储的金额分别是 1,2,3,4,5,6,7。这里是不是可以理解为每天在存储 1 块钱的基础上,分别还要存储 0,1,2,3,4,5,6 块钱。
所以,我们可以使用一个变量 day 表示当前的天数,以及表示今天还要额外存储多少钱,那每天存的钱就是 weeks + day。
最后,在 day 等于 7 时,说明这一周已经过完了,到了下一周,weeks + 1(基础存款金额 +1)。
public int totalMoney(int n) {
// 周数
int weeks = 1;
// 天数
int day = 0;
// 总金额
int totalMoney = 0;
// 总共循环 n 次
for(int i = 0;i < n; i++ ){
totalMoney += day + weeks;
++day;
if(day == 7){
//到下一周了
++weeks;
day = 0;
}
}
return totalMoney;
}
暴力法的时间复杂度是O(n),空间复杂度是O(1)。
公式法
我们高中就学过了等差数列的求和,这里刚好也是一个等差数列,所以我们可以使用等差数列来求出总金额。
等差数列求和公式:Sn=n*a1+n(n-1)d/2 或 Sn=n(a1+an)/2
我们需要分为两种情况来处理,一种是完整的一周,另一种是不完整的一周,至于为啥,接着往下看。
- 都是完整的一周,存多少钱
我们使用第一个公式,就可以求出一周内额外需要存储的钱 = 7 * 0 + 7(7-1)1/2 = 21。
那知道了一周额外需要存储的钱 (这个数可以直接写死),我们在加上每周基础要存的钱就行了。
假设有五周,第一周一天基础存 1,第五周一天基础存 5。
五周基础存的钱
= 7 * 每周第一天存的钱的和
= 7 * (n*a1+n(n-1)d/2)
= 7 * (5 * 1 + 5(5-1)1/2)
= 7 * 15 = 105.
那五周存的钱 =
5 * 一周额外需要存储的钱 + 五周基础存的钱 = 210.
使用暴力法验算正确√。
得出公式: (n = 完整周数)
n 个完整周存的钱 = n * 21 + 7 * ( n + n(n-1) / 2)
这里是仅限从第一周开始是完整周的计算方式,如果第一个周不是完整周,那就是下一种情况了。
- 在不完整的一周内,存多少钱
假设题目给出的天数是 17 天,那么现在是第三周,还剩三天。
第三周第一天要存 3,第三天要存 6。
利用求和公式:Sn=n(a1+an)/2
第三周要存的钱
= 3 ( 3 + 5 ) /2
= 12
得出公式;( day = 非完整周的天数,fristMoney = 非完整周第一天要存入多少钱)
非完整周存的钱 = day ( fristMoney + fristMoney + day - 1 )/2
(简化)= day ( fristMoney * 2 + day -1 )/2
两条公式都搞定了,剩下的就是
- 求出有多少个完整周。
- 非完整周是第几周,还剩几天了
这两个我觉得难不倒各位。
开始敲代码!
public int totalMoney(int n) {
int completeWeeks = n / 7;
int incompleteWeekDays = n % 7;
// n 个完整周存的钱 = n * 21 + 7 * ( n + n(n-1) / 2)
int completeWeeksMoney = completeWeeks * 21 + 7 * ( completeWeeks + (completeWeeks * (completeWeeks - 1 ) /2 ));
// day ( fristMoney * 2 + day -1 )/2
// 非完整周数的第一天的金额是完整周数 + 1
int fristMoney = completeWeeks + 1;
int incompleteMoney = incompleteWeekDays * ( fristMoney * 2 + incompleteWeekDays -1 ) / 2;
return completeWeeksMoney + incompleteMoney;
}
成绩非常不错!
最后
今天就到这里了。
这里是程序员徐小白,【每日算法】是我新开的一个专栏,在这里主要记录我学习算法的日常,也希望我能够坚持每日学习算法,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。