【力扣刷题】1103. 分糖果 II(暴力法 + 数学法求解)

221 阅读3分钟

「这是我参与11月更文挑战的第 17 天,活动详情查看:2021最后一次更文挑战

原题链接

1103. 分糖果 II - 力扣(LeetCode) (leetcode-cn.com)

题目描述

排排坐,分糖果。

我们买了一些糖果 candies,打算把它们分给排好队的 n = num_people 个小朋友。

给第一个小朋友 1 颗糖果,第二个小朋友 2 颗,依此类推,直到给最后一个小朋友 n 颗糖果。

然后,我们再回到队伍的起点,给第一个小朋友 n + 1 颗糖果,第二个小朋友 n + 2 颗,依此类推,直到给最后一个小朋友 2 * n 颗糖果。

重复上述过程(每次都比上一次多给出一颗糖果,当到达队伍终点后再次从队伍起点开始),直到我们分完所有的糖果。注意,就算我们手中的剩下糖果数不够(不比前一次发出的糖果多),这些糖果也会全部发给当前的小朋友。

返回一个长度为 num_people、元素之和为 candies 的数组,以表示糖果的最终分发情况(即 ans[i] 表示第 i 个小朋友分到的糖果数)。

测试用例

示例 1:

输入:candies = 7, num_people = 4
输出:[1,2,3,1]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0,0]。
第三次,ans[2] += 3,数组变为 [1,2,3,0]。
第四次,ans[3] += 1(因为此时只剩下 1 颗糖果),最终数组变为 [1,2,3,1]

参数限制

  • 1 <= candies <= 10^9
  • 1 <= num_people <= 1000

分析

最简单的,直接暴力法,初始化一个定长的数组,默认值为 0,按照题目的要求,第 n 次操作将 n 和对应的数组下标的数值相加并存入,如果第 n 次操作时,剩余的糖果数小于等于 n, 则在操作完成后,结束循环

因为数组可能会被折叠,即本来需要操作 n 次,但数组的长度 len 小于 n,那么我们需要处理的下标数据就是 n 对 len 取模

代码

var distributeCandies = function(candies, num_people) {
    let arr = new Array(num_people).fill(0);
    let i = 0,
        n = 1;
    for (; true;i++, n++) {
        if (i == num_people) i = 0;
        if (candies <= n) {
            arr[i] = arr[i] + candies;
            break;
        } else {
            arr[i] = arr[i] + n;
            candies -= n;
        }
    }
    return arr
};

image.png

优化

如果抛开数组的定长限制,n 个糖果从 1 开始自增摆放的话,可以摆 i 列,其中第 i 列的数可能小于等于 i

对一个递增且步进为 1 的数组进行求和,数组有 i 项,则和为 (x+1)*x/2,根据一元二次项的函数求解,可以知道 i=2n+1/21i = \sqrt{2n+1/2} - 1

由于最后一项可能不是刚好为 i,即上表达式计算的结果可能带小数,我们向上取整即知道有多少项,通过 (i+1)*i/2 - n 则知道了最后一项还差多少即可按照规则满上

现在,我们再将数据折叠,合并计算到有限长度数组中的对应下标即可

通过数学方式的计算,会优于暴力求解


今天的力扣刷题就分享到这里,感谢大家的阅读~