贪心算法之分糖果

来源:互联网 发布:我的世界清空玩家数据 编辑:程序博客网 时间:2024/06/05 16:45
前几天一位同学向我推荐了一道算法题,想了一会觉得思路有了,然后某天晚上想把代码撸出来,然后没想到的是:“一入此题深似海,从此头发是路人”。

———————————————————————## 标题 ##
这里写图片描述
题目的意思大致如下:现在你家里有一群小孩,站成一排,你要给他们分糖果。要求是:相邻两个人之间,年龄大的糖果数量要分的多,(如果相邻两个人年龄一样的话,两人的糖果数量大小没有要求)。你的目标是怎么用最少的糖果满足这些孩子的要求。
题目理解还是挺简单的,感兴趣的同学可以先想想看。这是检验智商的时候到了。
接下来,我将给出自己的解答。仅供参考。
刚好前段时间看了一点“贪心算法”。看到题目之后就自然而然的往“贪心”方面去设计。(贪心算法简要的说就是求解一个大问题的最优解时,每一小步都采取当前最优的策略,最终得到整体最优解,还不懂得自行百度吧)然后设计出来的算法就是:从第一个人开始,给他一个糖果,让往后走,若后一个人比前一个人年龄大,则他的糖果在前一个人的基础上加一,如果若后一个人比前一个人年龄小,则他的糖果在前一个人的基础上减一,如果减到零的话,就往前找到糖果一直减少的第一个人,从他开始,往后每人加一个糖果。
举个小例子,比如这群小孩的年龄如下:3,5,10,9,4,3。那么这个算法的执行过程就是,第一个人1个,第二个人2个,第三个人3个。第四个人2个,第五个人1个,此时发现第六个人只有0个了,让就从第三个人开始,每人加一个糖果。最后一个人就可以分一个了。这样就很愉快的完成任务了,花了一点时间把代码敲出来了。好开心。
结果一测试,很多结果不是最优解。吓的我只能重新考虑一下算法。在损伤了一些脑细胞之后发现,”减一“这个操作会有bug。比如上面的例子去掉后面两个人,即3,5,10,9。按照原来的算法是:1,2,3,2。但是你会发现最少的分发其实是:1,2,3,1。这只是一个简单的例子,还有很多更复杂的情况。于是我果断调整策略:每次只要后一个人的年龄比前面一个人小,我就给他一个糖果。遇到某人没有糖果发的时候,处理方法依旧如上。
代码改完之后,果然对了很多,然后发现我还没考虑相等的情况。(原题里也没说相等怎么办,自行脑补了一下)每次遇到相等的情况,就只给他一个。其它处理方法依旧不变。
好了,算法的设计终于告一段落了。但是接下来蛋疼的是撸代码了。可能是好久没编了,即使有了这个算法然后编出来还是有错。具体实现起来还是不简单的。比如怎么记录从谁开始一直下降,还有。。。。。。等细节问题。然后开始调试,各种改动,此处省略一千字。。。接下来附上代码了:

int candy(int* ratings, int ratingsSize) {    int min = 0;    int number = 1;    int current;    int i;    int count=0;    int a;    for (a = 0; a < ratingsSize-1; a++)    {        if(ratings[a]==ratings[a+1])        {            break;        }        else if (ratings[a] > ratings[a + 1])            count++;        else            break;    }    min = count+1;    for (i = 1; i < ratingsSize; i++)    {        if (ratings[i]>ratings[i - 1])        {            number++;            min = min + number;        }        else if (ratings[i] == ratings[i - 1])        {            number = 1;            min = min + number;        }        else        {            count = 0;            for (current = i; current < ratingsSize; current++)            {                if (ratings[current] < ratings[current - 1])                {                    count++;                    min = min + count;                }                else                {                    break;                }            }            if(count>=number&&i!=1)            {                min=min+count-number+1;            }            number = 1;            i = current-1;        }    }    return min;    }
改了几个错误,提交之后,A了。真是来之不易的幸福,o(* ̄▽ ̄*)o。解释一下代码:第一个for循环是为了处理,前面的人的年龄都相等的情况。直接给他们每人一个。(其实是放在大循环了没改出来,两者的时间复杂度也差不多)。number是记录当前这个人的糖果的数量,遇到后一个人年龄大与等于当前这个人的话,比较好处理。如果后一个人年龄小于前一个人的话,就一直找到年龄开始上升的两个人。计算这段年龄递减的人所需的糖果数量。这个程序虽然有两重循环,但实际上时间复杂度依旧为O(n)。 总的来说,这道题看上去不是很难,但是要想到各种情况的算法还是有一定难度的,可能会遗漏一些情况。这就是算法的严密性。突然记起和某位大佬写一道算法题,就是一个数组中只有一个数出现了一次,其它数都出现了三次,把那个出现一次的数找出来。结果算法逻辑漏了一些情况。在交流的时候还肯定的说我的算法没问题,很简单的解释了一下。结果就很尴尬了,认真一想发现漏了情况,其实算法也就是错的。真是打脸啪啪响。   算法是很挑战思维的东西,能够独立思考出一些算法题是很有成就感,特别是找到了较优 的解法。其次设计的过程中,逻辑关系要理清楚,否则很容易出错或者遗漏情况。比如我现在都不能确定上面的算法是不是符合所有的情况,毕竟平台只有29个测试用例。

0 0
原创粉丝点击