LeetCode 16.分糖果问题 暴力破解法和数学方法之间的差距

题目描述

排排坐,分糖果。

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

 

解题思路

方法一:暴力破解,也叫模拟问题法,普通遍历,while循环内嵌for循环即可

方法二:找规律,利用等差数列

代码如下

代码一:

package leetcode;

public class DistributeCandies {
    public int[] distributeCandies(int candies, int num_people) {
        int[] nums_people=new int[num_people];
        int flag=0;
        while (candies!=0) {
            
            for (int i = 0; i < nums_people.length; i++) {
                int temp=flag*num_people+i+1;
                if (candies>temp) {
                    candies-=temp;
                    nums_people[i]=nums_people[i]+temp;
                }else {
                    nums_people[i]=nums_people[i]+candies;
                    candies=0;
                }
            }
            if (candies!=0) {
                flag++;
            }
            
        }
        
        
        
        return nums_people;

    }
}

代码二:

class Solution {
    private int n ;//总人数
    private int times;//分发次数,不足分发这一次的全部,也算1次
    private int last;//最后分配到的那个人(糖果数量足够),也就是left变量是last的下一个分配对象
    private int candies;
    private int left;//最后要分配糖果数不够(不比前一次发出的糖果多))
    public int[] distributeCandies(int candies, int num_people) {
        this.n = num_people;
        this.candies = candies;
        int[] res = new int[n];
        init();
        //对每一个人分配糖果
        for (int index = 0; index < n; index++) {
            if(index <= last)
                 res[index] = ((index+1)*times)+(times*times-times) * n /2;
            else {
                res[index] = ((index + 1) * (times-1)) + ((times-1) * (times-1) - (times-1)) * n / 2;
            }
        }
        //最后把糖果数不足的分配出去
        res[(last+1)%n] += left;
        return res;
    }

    private void init(){
        int times = 1;
        while(candies > 0){
            candies -= oneSum(n,times);
            times++;
        }
        times-=1;
        candies +=oneSum(n,times);
        int last = 0;
        while (candies >= (times-1)*n+last+1){
            candies -= (times-1)*n+last+1;
            last++;
        }
        this.left = candies;
        this.times = times;
        this.last  = last-1;
    }

    /**
     * @param num_people
     * @param times 能分配的次数
     * @return 需要分配出去的糖果数量
     */
    private int oneSum(int num_people,int times){
        return (1+n) * num_people / 2  + (times-1) * n * n;//等差数列求和
    }

}
原文地址:https://www.cnblogs.com/Transkai/p/12421781.html