• 135.Candy---贪心


    题目链接

    题目大意:分糖果,每个小朋友都有一个ratings值,且每个小朋友至少都要有一个糖果,而且每个小朋友的ratings值如果比左右邻舍的小朋友的ratings值高,则其糖果数量也比邻舍的小朋友多。

    法一:超时。按照要求,从前往后比较每个小朋友的ratings值,如果后一个小朋友的ratings值比前一个大,则更新小朋友糖果值dp[i]=dp[i-1]+1;否则,将当前小朋友的糖果值置1,然后考察其前一个小朋友糖果值是否满足dp[i-1]<=dp[i],且ratings[i-1]>ratings[i],如果满足这两个条件,则说明前小朋友的糖果值需要更新,且需要循环遍历更新前面小朋友的糖果值。o(n^2)。代码如下:

     1     public int candy(int[] ratings) {
     2         int len = ratings.length;
     3         if(len == 0) {
     4             return 0;
     5         }
     6         else if(len == 1) {
     7             return 1;
     8         }
     9         int[] dp = new int[len];
    10         //初始化第一个小伙伴的糖果值
    11         dp[0] = ratings[0] <= ratings[1] ? 1 : 2;
    12         int cnt = 0;
    13         for(int i = 1; i < len; i++) {
    14             //只与前面小伙伴的ratings进行比较
    15             if(ratings[i] > ratings[i - 1]) {
    16                 dp[i] = dp[i - 1] + 1;
    17             }
    18             else {
    19                 dp[i] = 1;
    20                 //如果前面小伙伴的糖果是1,且ratings比较高,则遍历其前面的所有小伙伴
    21                 if(dp[i - 1] == 1 && ratings[i - 1] > ratings[i]) {
    22                     //更新前面的小伙伴的糖果值,因为这个更新,对于这种用例5,3,1,这个小伙伴前面的所有糖果值都要更新,所以进入下面的for循环进行判断
    23                     dp[i - 1] = 2;
    24                     for(int j = i - 2; j >= 0; j--) {
    25                         //如果前面的小伙伴的糖果值小,且ratings又比较高,则更新其值
    26                         if(ratings[j] > ratings[j + 1] && dp[j] <= dp[j + 1]) {
    27                             dp[j] = dp[j + 1] + 1;
    28                         }
    29                         else {
    30                             break;
    31                         }
    32                     }
    33                 }
    34             }
    35         }
    36         //计算所有的糖果值
    37         for(int i = 0; i < len; i++) {
    38             cnt += dp[i];
    39         }
    40         return cnt;
    41     }
    View Code

    法二(借鉴):两个数组,一个数组从前往后遍历,一旦ratings值比前一个大,则dp[i]=dp[i-1]+1;一个数组从后往前遍历,一旦ratings值比后一个大,则dp[i]=dp[i+1]+1。最后从这两个数组中取一个较大者,计算最终糖果值。o(n)。当然也可以用一个数组,但是思想逻辑都是一样的,只是如果用一个数组的话,就是从后往前遍历得到的新值与当前数组值进行比较,取较大者就是了。代码如下(耗时5ms):

     1     public int candy(int[] ratings) {
     2         int len = ratings.length;
     3         if(len == 0) {
     4             return 0;
     5         }
     6         else if(len == 1) {
     7             return 1;
     8         }
     9         int[] left_candy = new int[len];
    10         int[] right_candy = new int[len];
    11         //初始化
    12         left_candy[0] = ratings[0] <= ratings[1] ? 1 : 2;
    13         right_candy[len - 1] = ratings[len - 1] <= ratings[len - 2] ? 1 : 2;
    14         //从前往后遍历
    15         for(int i = 1; i < len; i++) {
    16             if(ratings[i] > ratings[i - 1]) {
    17                 left_candy[i] = left_candy[i - 1] + 1;
    18             }
    19             else {
    20                 left_candy[i] = 1;
    21             }
    22         }
    23         //从后往前遍历
    24         for(int j = len - 2; j >= 0; j--) {
    25             if(ratings[j] > ratings[j + 1]) {
    26                 right_candy[j] = right_candy[j + 1] + 1;
    27             }
    28             else {
    29                 right_candy[j] = 1;
    30             }
    31         }
    32         //两者中取较大者,计算糖果值
    33         int cnt = 0;
    34         for(int i = 0; i < len; i++) {
    35             cnt += Math.max(left_candy[i], right_candy[i]);
    36         }
    37         return cnt;
    38     }
    View Code

    法三(借鉴):最优解。只遍历一遍,o(n)。一旦遍历到递减rating,则计数递减的个数,而暂停计算其糖果值;当遍历到递增rating时,则开始计算前面递减的小朋友的糖果值,以及当前小朋友的糖果值。具体注释看代码。代码如下(耗时5ms):

     1     public int candy(int[] ratings) {
     2         int first = 1, cnt = 0, res = 1, len = ratings.length;
     3         for(int i = 1; i < len; i++) {
     4             //如果比前一个小朋友rating高,则计算总糖果值
     5             if(ratings[i] >= ratings[i - 1]) {
     6                 //如果当前小朋友前面有递减rating,先处理这几个小朋友的糖果值
     7                 if(cnt > 0) {
     8                     //从递减的第二个数开始,到最后一个递减rating结束为止,这几个小朋友的糖果总值就是cnt * (cnt + 1) / 2
     9                     res += cnt * (cnt + 1) / 2;
    10                     //处理开始递减的第一个数,即将其需要增加的糖果数cnt-res+1,加入res中
    11                     if(cnt >= first) {
    12                         res += cnt - first + 1;
    13                     }
    14                     //重置
    15                     cnt = 0;
    16                     first = 1;
    17                 }
    18                 //对于当前第i个小朋友,正常计算其糖果值,将其加入res结果中
    19                 first = (ratings[i] == ratings[i - 1]) ? 1 : first + 1;
    20                 res += first;
    21             }
    22             //计数递减rating的个数
    23             else {
    24                 cnt++;
    25             }
    26         }
    27         //处理最后一组递减rating,而其后没有再反弹的小伙伴,即一直递减,不满足ratings[i] >= ratings[i - 1]就到数组终结
    28         if(cnt > 0) {
    29             res += cnt * (cnt + 1) / 2;
    30             if(cnt >= first) {
    31                 res += cnt - first + 1;
    32             }
    33         }
    34         return res;
    35     }
    View Code
  • 相关阅读:
    Linux 下没有 my.cnf 文件的解决方式,完全是我自己整的,好多教程都是瞎扯的 (zhuan)
    Virtualbox虚拟机安装CentOS6.5图文详细教程(zhuan)
    virtualbox中centos系统配置nat+host only上网(zhuan)
    VirtualBox的网络配置,Host Only+NAT方式 (zhuan)
    Linux上安装Mysql后除了本机其他机器不能访问的问题(zhuan)
    VirtualBox没有64位选项,无法安装64位的解决方法(zhuan)
    CentOS查看内核版本,位数,版本号 (zhuan)
    datagrid实现单行的选择、取消
    datagrid实现行的上移和下移
    Excel 、数据库 一言不合就转换 (zhuan)
  • 原文地址:https://www.cnblogs.com/cing/p/8745087.html
Copyright © 2020-2023  润新知