LeetCode#第135题:分发糖果(困难题&&滤波器解法)

接下来我们把难度功率拉满,剑指offer!

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
     第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。

分析

        对于控制、电子相关专业的读者朋友来说,仔细读完这道题,是否有点似曾相识的感觉?

        题目本质上是让把评分序列转化为一个能够反应评分大小关系的幅度最小序列,然后进行积分。这看起来是不是有点像滤波算法啊?(*^_^*)|||

        如果学过数字信号处理或者信号与系统的话,应该能很容易看出来,将评分输入转换为最小糖果数集的系统是一个典型的特征提取系统。

        例如,我们从采样电路中采集的模拟量经过ADC转换为数字序列 [1,6,10,8,7,3,2] , 经过题设的特征提取后成为[1,2,5,4,3,2,1], 特征积分量 也就是我们的最小糖果总数为18.

        过程如下图所示,

LeetCode#第135题:分发糖果(困难题&&滤波器解法)_第1张图片

        接下来就很好理解了,我们最终目标是让特征积分最小,根据贪心算法,我们的滤波器的特征提取算法应该是:

        1. 快指针开始遍历整个数字序列,慢指针指向开头、波峰或波谷;

        2. 每遍历到一个元素,如果处在递增段则给积分加fast本位值,如果在稳态则稳态特征量默认为1(因为题目中只定义了相邻不相等要求响应满足对应大小关系,没要求相邻相等的情况),如果在递减段则先对波峰后的元素进行处理,即遍历一个对sum+=fast-slow(因为要满足相邻大小关系,你的下一位被赋值了,上面几位也需要进行补偿,俄罗斯方块的意思,这样能懂吧?)

       3. 这里只处理波峰之外的点,对此次降幅和上次幅度进行对比,如果降幅小于等于上次幅度,则对波峰补偿标志位置为false;如果大于上次幅度,则将标志位置为true,等待后续对波峰的补偿。

       4. 在没有遍历到最后一个元素时,进行增减稳状态判断,如果增并且与当前状态矛盾,fast则指向了波峰。把慢指针slow移到波峰。如果减并且与当前矛盾,fast则指向了波谷,进行幅度迭代,并更新slow到波谷。如果接下来是稳态,并且与之前状态矛盾,进行幅度迭代,并指向稳态响应拐点。从递减进入判断前,必须进行一次波峰补偿(因为当降幅大于上次幅度,递减的第一个元素大小必然比波峰要大,这是不符合题意的),补偿公式:

                         sum += fast - slow - last_Amplitude

      5. 末尾情况下若遇到补偿标志位,也需要进行补偿

     6. 重复上述内容,直至积分完成

代码实现

int candy(int* ratings, int ratingsSize) {
    int sum=0;
    //积分初始化
    int slow=0,fast;
     //快慢指针
    int last_Amplitude=0;
    //上次上升幅度
    int status=0;
    //增减、稳定、下降状态
    bool cmpst=false;
    //波峰补偿标志位
    for (fast=0; fast*(fast+ratings+1)){
                //下降拐点
                last_Amplitude=fast-slow;
                //更新上升幅度
                slow=fast;
                status=-1;
                continue;
            }
            if((status==-1||status==0)&&*(fast+ratings)<*(fast+ratings+1)){
                 //上升拐点    
                 if(cmpst==true){
                    //判断波峰补偿
                    sum+=fast-slow-last_Amplitude;
                    cmpst=false;
                }
                slow=fast;
                status=1;
                continue;
            }
        }
        if(fast==ratingsSize-1&&cmpst==true){
            //末尾波峰补偿,注意边界条件
            sum+=fast-slow-last_Amplitude;
        }
    }
    return sum;
}

        从这道题看出来,其实写算法的时候,遇到传统方法很难解决的问题,运用系统辨识法,把难以理解的问题转化为单纯的信号处理问题,利用滤波/控制/反馈等等思想去解决,也是可行的。

        

 

你可能感兴趣的:(leetcode,算法,数据结构)