1103、分糖果II

  1. 1103、分糖果II
    1. 示例 1:
    2. 示例 2:
  2. 题解
    1. 1、模拟分配
    2. 2、计算组数,至多循环两次
    3. 3、先一次性分配到位,再从后往前去除超额的。
    4. 4、等差数列求和

1103、分糖果II

排排坐,分糖果。

我们买了一些糖果 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]。

示例 2:

输入:candies = 10, num_people = 3
输出:[5,2,3]
解释:
第一次,ans[0] += 1,数组变为 [1,0,0]。
第二次,ans[1] += 2,数组变为 [1,2,0]。
第三次,ans[2] += 3,数组变为 [1,2,3]。
第四次,ans[0] += 4,最终数组变为 [5,2,3]。

提示:

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

链接:https://leetcode-cn.com/problems/distribute-candies-to-people

题解

1、模拟分配

利用取模运算直接分配。

public class Solution {
    public int[] distributeCandies(int candies,int num_people) {
        int[] res = new int[num_people];
        int count = 0;
        while (candies > 0) {
            if (candies >= count+1){
                res[count%num_people] += count+1;
            }else {
                res[count % num_people] += candies;
                break;
            }
            candies -= count+1;
        }
        return res;
    }
}

class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        // 模拟
        int[] ans = new int[num_people];

        int base = 1;// current candies to give
        int index = 0;
        while (candies > 0) {
            if (candies >= base) {
                candies -= base;
                ans[index] += base;
            } else {
                ans[index] += candies;
                candies = 0;
            }
            base++;
            index++;
            index = index%num_people;
        }

        return ans;
    }
}

2、计算组数,至多循环两次

  • 先计算可以分配的组数有多少:

candies个糖果分配给num_people个小朋友。
第i组需要的糖果数量为:
$$
a_i = \frac{n(n+1)}{2} + (i - 1) · n^2
= \frac{(2·i - 1)n^2 + n}{2}
$$

  • 然后,将可以完全分配的组数先分配。

假如我们计算了需要分配count次,那么,最后一次算作不完全分配。我们可以对前count-1次进行统一分配,因为相邻的小朋友,固定相差count-1个糖果。

对于第一个小朋友:
第i组分配到的糖果数量为:

$$ a_0 = 1,a_i = 1 + (i - 1)*n,$$

那么第一位同学分配到第i组时,总共的糖果数量为:

$$ S_i = (1 + 1 + (i - 1)·n)*i/2 $$

之后的,同学与前一位同学的糖果数量关系为:

$$ s_i = s_{i - 1} + count - 1; $$

  • 处理最后一组的不完全分配。

最后一组( 第count组 ),第一位同学应该分配的糖果数量为:

$$ a_{count} = 1 + n(count - 1) $$

然后,模拟分配即可。

class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        int[] res = new int[num_people];
        // 第一轮需要的所有的糖果数量
        int sum = (1+num_people)*num_people/2;
        int count = 1;
        // 统计可以分多少组
        while (candies >= sum) {
            count++;
            sum += ((2*count-1)*num_people*num_people + num_people)/2;
        }
        if (count == 1) { // 只有一组
            for (int i = 0;i < num_people;i++) {
                if (candies < i) {
                    res[i] = candies;
                    break;
                }else {
                    res[i] = i+1;
                    candies -= i+1;
                }
            }
        } else { // 存在多组
            // 计算第一位同学可以获得的 前count - 1组的糖果数量
            int first = (1 + (count-2)*num_people + 1)*(count-1)/2;
            // 推到出所有同学的糖果数量
            for (int i = 0;i < num_people;i++) {
                if (i == 0) {
                    res[i] = first;
                } else {
                    // 第i为同学的糖果数量比前一位同学的多count - 1个
                    res[i] = res[i-1] + count - 1;
                }
                candies -= res[i];
            }
            // 处理最后一行的糖果分配,因为可能分配不全。
            // 最后一组分配的
            first = 1+num_people*(count-1);
            for (int i = 0;i < num_people;i++) {
                if (candies >= first) {
                    res[i] += first;
                    candies -= first;
                    first++;
                }else {
                    res[i] += candies;
                    break;
                }
            }
        }
        return res;
    }
}

3、先一次性分配到位,再从后往前去除超额的。

不用再分情况分配了。

class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        int[] res = new int[num_people];
        // 第一轮需要的所有的糖果数量
        int sum = (1+num_people)*num_people/2;
        int count = 1;
        // 统计可以分多少组
        while (candies >= sum) {
            count++;
            sum += ((2*count-1)*num_people*num_people + num_people)/2;
        }
        // 计算第一位同学可以获得的 前count - 1组的糖果数量
        int first = (1 + (count-1)*num_people + 1)*(count)/2;
        // 推到出所有同学的糖果数量
        for (int i = 0;i < num_people;i++) {
            if (i == 0) {
                res[i] = first;
            } else {
                // 第i为同学的糖果数量比前一位同学的多count - 1个
                res[i] = res[i-1] + count;
            }
            candies -= res[i];
        }
        // 说明最后一组超额分配了
        if (candies < 0) {
            int last = count*num_people;
            for (int i = num_people - 1;i >= 0;i--) {
                if (candies + last <= 0) {
                    // 多分配了last个
                    res[i] -= last;
                } else {
                    // 第一个多分配的同学,多分配了 -candies个
                    res[i] -= -candies;
                    break;
                }
                candies += last;
                last--;
            }
        }
        return res;
    }
}

4、等差数列求和

求出当前糖果数可以多少人:

$$ S_n = \frac{(n+1)n}{2} $$

找到最后一个小于candies的$S_n$,把candies带进去进行计算即可:
求根公式:
$$ candies = \frac{(n+1)n}{2} $$
$$a=1,b=1,c=-2candies$$
$$
n = \frac{-1+_-\sqrt{1+8
candies}}{2}
$$
化简:

$$
p = floor({-\frac{1}{2}+\sqrt{\frac{1}{4}+2*candies}})
$$
剩余没能按照规则发的糖果:
$$
last_candies = candies - \frac{p(p+1)}{2}
$$

可以计算发了多少轮:取商
$$ rows = p / num_people $$

class Solution {
    public int[] distributeCandies(int candies, int num_people) {
        int n = num_people;
        // how many people received complete gifts
        int p = (int) (Math.sqrt(2 * candies + 0.25) - 0.5);
        int remaining = (int) (candies - (p + 1) * p * 0.5);
        int rows = p / n, cols = p % n;

        int[] d = new int[n];
        for (int i = 0; i < n; ++i) {
            // complete rows
            d[i] = (i + 1) * rows + (int) (rows * (rows - 1) * 0.5) * n;
            // cols in the last row
            if (i < cols) {
                d[i] += i + 1 + rows * n;
            }
        }
        // remaining candies      
        d[cols] += remaining;
        return d;
    }
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

💰

Title:1103、分糖果II

Count:1.6k

Author:攀登

Created At:2020-07-26, 00:19:44

Updated At:2024-06-15, 15:52:32

Url:http://jiafeimao-gjf.github.io/2020/07/26/1103%E3%80%81%E5%88%86%E7%B3%96%E6%9E%9CII/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

Help us with donation