【每日算法】力扣1716. 计算力扣银行的钱

225 阅读4分钟

「这是我参与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;
    }

image.png

暴力法的时间复杂度是O(n),空间复杂度是O(1)。

公式法

我们高中就学过了等差数列的求和,这里刚好也是一个等差数列,所以我们可以使用等差数列来求出总金额。

等差数列求和公式:Sn=n*a1+n(n-1)d/2 或 Sn=n(a1+an)/2

我们需要分为两种情况来处理,一种是完整的一周,另一种是不完整的一周,至于为啥,接着往下看。

  1. 都是完整的一周,存多少钱

我们使用第一个公式,就可以求出一周内额外需要存储的钱 = 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)

这里是仅限从第一周开始是完整周的计算方式,如果第一个周不是完整周,那就是下一种情况了。

  1. 在不完整的一周内,存多少钱

假设题目给出的天数是 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

两条公式都搞定了,剩下的就是

  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;
    }

image.png

成绩非常不错!

最后

今天就到这里了。

这里是程序员徐小白,【每日算法】是我新开的一个专栏,在这里主要记录我学习算法的日常,也希望我能够坚持每日学习算法,不知道这样的文章风格您是否喜欢,不要吝啬您免费的赞,您的点赞、收藏以及评论都是我下班后坚持更文的动力。