滞在ボタントピック住所:https://leetcode-cn.com/problems/distribute-candies-to-people/
主題を初めて目:
たけた、サブキャンディ。
我々は、彼らがキューイングされ、N = NUM_PEOPLE 2人の子供を提供するつもりされている、いくつかのキャンディキャンディを買いました。
最初の菓子の子、第二の二人の子供、というように、キャンディのn個の最後の子まで。
その後、私たちはお菓子の2人の* n次の作品への最後の子まで、その上のキャンディー子供のn + 1の最初の部分に、戻ってチームのスタート地点に戻り、N + 2番目の子の星、と。
プロセス(およびチームが再びチームのために始めて開始点から最後に到着したお菓子、与えられた最後のより多くのたびに)我々はすべてのサブお菓子を終えるまでを繰り返します。残りは私たちの手の中にない場合でも、お菓子の数(回以上発行する前にキャンディー)は、これらのキャンディーは、現在のすべての子どもたちに配布されることに注意してください。
NUM_PEOPLE長の配列、およびキャンディーの要素に対する戻り値(すなわちANS [I]は、i番目の数子に割り当てられたキャンディを表す)キャンディー最終分布の場合を表現します。
例:
示例一:
输入: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]。
示例二:
输入: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
ソリューション:
この質問は、人々が最初に考えるのソリューションですが推定するブルートフォース方法です。次いで、アレイを返し、配列の要素の一定数のキャンディを計算すると、現在のツリーキャンディキャンディを残りの必要な数よりも大きい場合には全体ではなく現在の要素の部分があれば、キャンディは、割り当て要求される要求しました。
私は個人的にこのブルートフォースは、いくつかのルールで時間を節約するための解決策を見つけようとするので、このアプローチのない使用がない、とは思いません。
このブログは、今日だけリリースされた理由です。あなたの隣には、私のショーの操作について話しています。
私たちの旅を解決する起動します。
私は、おそらくこれである考え。まず、私はキャンディーやお菓子配列NUM_PEOPLEの合計数の要素数を知っています。
最初のステップ:お菓子の各要素が増え割り当てられているので、どのくらいのお菓子合計私はNUM_PEOPLEの必要性を循環が完全にすべてのを知っていることができそう。私たちは、何回現在のサイクルを計算し、合計やキャンディーの大きさを比較します。
ステップ二:次に、我々の総いくつかのキャンディの現在のサイクルにキャンディサイクルの総数を減算し、差分値を算出し、最後に完成したキャンディ要素位置END_INDEXを計算するために、逆方向ワンQianmian現在のサイクルに由来します。
第三段階:END_INDEXを計算した後、我々は、他の要素がEND_INDEX合計カウント+ 1サイクル未満であることを知って、最初の要素が残っている数とキャンディの和END_INDEXサイクル数であり、要素が他の要素がEND_INDEXよりも大きいです最初のカウント周期の和です。
コードの実装の最初のステップ:
第一次循环分配糖果总和:从 1 到 num_people
递增正整数列求和公式:sum = (1+n)n/2;
循环示例:
第一次循环:1 到 num_people
int sum1 = (1+num_people)*num_people/2;
第二次循环:num_people+1 到 2*num_people
int sum2 = (1+3*num_people)*num_people/2;
第三次循环:2*num_people+1 到 3*num_people
int sum3 = (1+5*num_people)*num_people/2;
第四次循环:3*num_people+1 到 4*num_people
int sum4 = (1+7*num_people)*num_people/2;
总结规律:
完成第 count 次循环所需糖果数量总和:
(1+(2*count-1)*num_people)*num_people/2
代码实现:
//知道了规律我们接下来就可以计算 循环次数
//完成循环次数;从0开始,因为不知道第一次循环的糖果是否能分配完
int count = 0;
//计算完成第一次循环需要的糖果数量
int sum = (1+num_people)*num_people/2;
//算出循环次数 判断总糖果数量是否大于循环增加的糖果数量总和
while (candies > sum){
//循环次数加一
count++;
//计算出下次循环所需要的糖果数 并加入sum
sum += (1+(2*(count+1)-1)*num_people)*num_people/2;
}
第二の工程コード実装:
1.注意count是完成循环的次数,并不是循环到的次数,所以我们能够循环到第count+1次循环。
2.计算出 candies 数量的糖果能够循环到第 count + 1次之后。
3.我们接下来要考虑的是我们如何定位到 count+1 次循环时,糖果分配完的那个元素位置。
4.首先利用上面计算循环次数的sum和糖果总数candies,计算出完成第count+1次循环所差的糖果值。
反向推导示例:
第 count 次循环最后 1 位所需糖果数:
int sub1 = count*num_people-0;
第 count 次循环倒数第 2 位所需糖果数:
int sub2 = count*num_people-1;
第 count 次循环倒数第 3 位所需糖果数:
int sub3 = count*num_people-2;
第 count 次循环倒数第 4 位所需糖果数:
int sub4 = count*num_people-3;
总结规律:
倒数第 sub_count 位所需要的糖果数:
count*num_people-sub_count
代码实现:
//计算差值
int sub = sum - candies;
//反向推导次数
int sub_count = 0;
//反向推导:倒数第一个位置所需要的糖果数量
int sub_now = (count+1)*num_people-sub_count;
//当剩余糖果数量小于下一个位置所需的糖果数量,说明剩余糖果不够分配给下一个位置了。
while(sub >= sub_now){
//下一个位置所需的糖果数量
sub_now = (count+1)*num_people-sub_count;
//剩余糖果数量减去当前位置所需糖果数量;
sub -= sub_now;
//完成反向推导次数+1
sub_count++;
}
//计算出下一个位置需要的糖果数
sub_now = (count+1)*num_people-sub_count;
//计算出下一个位置剩余的糖果数
sub = sub_now - sub;
//循环到糖果不足的位置
int end_index = num_people - sub_count;
第三の工程コード実装:
1.计算 end_index 之后;小于 end_index 的其他元素都是count+1次循环的总和。
2.第 end_index 元素是第count次循环的总和加上剩余糖果数量。
3.大于 end_index 元素的其他元素都是第 count 次循环的总和。
元素总和计算示例:
//计算每一位元素需要的值,并放入
第一次循环第一个元素所需糖果数总和:
int number1_1 = 1;
int number1_2 = 2+num_people;(1+1+num_people)
int number1_3 = 3+3*num_people;(1 + 1+num_people + 1+2*num_people)
int number1_4 = 4+6*num_people;
int number1_5 = 5+10*num_people;
int number1_6 = 6+15*num_people;
int number1_7 = 7+21*num_people;
int number1_8 = 8+28*num_people;
第二次循环第一个元素所需糖果数总和:
int number2_1 = 2;
int number2_2 = 4+num_people;
第三次循环第一个元素所需糖果数总和:
int number3_1 = 3;
int number3_2 = 6+num_people;
总结规律:
x 等于从 1 到 count 的和,递增正整数列求和公式:
x = (1+count)*count/2
第 count 次循环 第 i 个位置所需糖果总数:
count*(i+1) + x * num_people
代码实现:
//计算x的值
int x = count*(count+1)/2;
//循环设置值
for(int i = 0; i < num_people; i++) {
if(i < end_index-1){
//1.小于 end_index 的其他元素都是count+1次循环的总和。
result[i] = (count+1)*(i+1) + x * num_people;
}else if(i == end_index-1){
//2.第 end_index 元素是第count次循环的总和加上剩余糖果数量。
result[i] = count*(i+1) +(x-count) * num_people + sub;
}else{
//3.大于 end_index 元素的其他元素都是第 count 次循环的总和。
result[i] = count*(i+1) +(x-count) * num_people;
}
}
完全なコード:
/**
* 分糖果 https://leetcode-cn.com/problems/distribute-candies-to-people/
* @param candies
* @param num_people
* @author GeYuxuan 2020-03-06 22:18:03
* @return int[]
*/
public int[] distributeCandies(int candies, int num_people) {
int [] result = new int[num_people];
//循环次数
int count = 0;
int sum = (1+num_people)*num_people/2;
//算出循环次数
while (candies > sum){
//循环次数加一
count++;
//计算出下次循环所需要的糖果数 并加入sum
sum += (1+(2*(count+1)-1)*num_people)*num_people/2;
}
//计算差值
int sub = sum - candies;
int sub_count = 0;
int sub_now = (count+1)*num_people-sub_count;
while(sub >= sub_now){
sub_now = (count+1)*num_people-sub_count;
sub -= sub_now;
sub_count++;
}
sub_now = (count+1)*num_people-sub_count;
sub = sub_now - sub;
//循环到余额不足的位置
int end_index = num_people - sub_count;
//计算count总和
int x = count*(count+1)/2;
//计算每一位需要的值,并放入
for(int i = 0; i < num_people; i++) {
if(i < end_index-1){
result[i] = (count+1)*(i+1) + x * num_people;
}else if(i == end_index-1){
result[i] = count*(i+1) +(x-count) * num_people + sub;
}else{
result[i] = count*(i+1) +(x-count) * num_people;
}
}
return result;
}
このブログは第3月5日に発行されなければならないの記事ですが、夜は問題が出て頭なかったことが三時間は、実際には、私はこのようなソリューションの途中であきらめることを考えていたが、私はどこ私の解決策を理解したくありませんでした問題。次の日は、私は次の日に再び質問には無料のソリューションを意図する作業に影響しないようにするためには、仕事に行くので。次の夜は、この疑問を解決するまでは、私はとても興奮しています。私は暴力は常に最後のソリューションになると思う、唯一の愚かは、彼の心は柔軟にできるようになります。
彼は前方に早く心、気性を忘れませんでした。