代码随想录算法训练营第三十四天|1005.K次取反后最大化的数组和 、134. 加油站、135. 分发糖果

目录

1005.K次取反后最大化的数组和

简单的对数组进行升序排列

对数组的绝对值进行降序排列

134. 加油站(×)

135. 分发糖果 (困难,没有加油站困难)


1005.K次取反后最大化的数组和

题目链接:1005. K 次取反后最大化的数组和

题目描述:

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

    选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

很容易想到对数组先进行排序,优先翻转负数,之后根据剩下的翻转次数决定是否再进行翻转。

简单的对数组进行升序排列

如果简单的对数组进行升序排列,其它都还好,但是对于最后翻转哪一个元素的判断要考虑的很多。比如下面例子:

                -8        -5        -5        -3        -2        3        (k=6)

翻转:      8         5         5         3          2        

k:              5         4         3         2          1

此时k=1需要翻转,为了使和最大应该再翻转一次-2。

                -2        1        2        3        (k=4)

翻转:     2  

k:             3

 此时k=3需要翻转,为了使和最大应该翻转的是1,而不是-2。

通过对数组进行简单的升序排列,在这个地方要考虑:

  1. 翻转还是不翻转
  2. 翻转第一个整数还是最大的负数
  3. 如果整个数组全是正数,没有负数们还要与2.相区分

要做的判断就太多了,有一种面向测试用例编程的感觉。

对数组的绝对值进行降序排列

                -8        3        -5        -3        -5        -2        (k=6)

排序后     -8        -5       -5        -3         3        -2

 同样优先将负数翻转,随后反转的必定是排序后的最后一个元素,也就是绝对值最小的元素,只需要判断是否翻转。

int cmp_int(const int* e1,const int* e2){
    return abs(*(int*)e2)-abs(*(int*)e1);
}
int largestSumAfterKNegations(int* nums, int numsSize, int k){
    //将数组按绝对值大小降序排列
    qsort(nums,numsSize,sizeof(int),cmp_int);
    int ret=0;
    for(int i=0;i<numsSize;i++){
        if(k>0&&nums[i]<0){
            nums[i]*=-1;
            k--;
        }
    }
    //反转绝对值最小的元素
    if(k>0&&k%2==1){
        nums[numsSize-1]*=-1;
    }
    for(int i=0;i<numsSize;i++){
        ret+=nums[i];
    }
    return  ret;
}

134. 加油站(×)

题目链接:134. 加油站

题目描述:

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

重新做的时候搞不懂逻辑就画画图!我自己肯定是想不到这样子做。

我觉得挺难理解的,Cral讲解视频:贪心算法,得这么加油才能跑完全程!LeetCode :134.加油站_哔哩哔哩_bilibili

int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
    //转一圈的剩余油量
    int total_gas=0;
    //记录当前油量
    int cur_gas=0;
    int ret=0;
    //如果总的消耗大于总共获取的油量,一定不能转一圈
    for(int i=0;i<gasSize;i++){
        total_gas+=gas[i]-cost[i];
    }
    if(total_gas<0)     return -1;
    }
    //只要能走完一圈,肯定有合适的路线
    for(int i=0;i<gasSize;i++){
        //每走一段当前油量+获得和消耗的差值
        cur_gas+=gas[i]-cost[i];
        //当前油量<0说明从从前面的站点到这个地方都行不通
        if(cur_gas<0){
            //从下个站点开始
            ret=i+1;
            //开始时油箱为0
            cur_gas=0;
        }
    }
    return ret;
}

135. 分发糖果 (困难,没有加油站困难)

题目链接:135. 分发糖果

题目描述:

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

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

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

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

这个是困难题!比加油站好理解得多啊!!!

左右遍历一遍各取最大值!

int candy(int* ratings, int ratingsSize){
    if(ratingsSize==1)  return 1;
    int* List=(int*)malloc(sizeof(int)*ratingsSize);
    //判断左<右
    List[0]=1;
    for(int i=1;i<ratingsSize;i++){
        if(ratings[i]>ratings[i-1]){
            List[i]=List[i-1]+1;
        }else{
            List[i]=1;
        }
    }
    //判断左>右
    List[ratingsSize-1]=fmax(1,List[ratingsSize-1]);
    int ret=List[ratingsSize-1];
    for(int i=ratingsSize-2;i>=0;i--){
        int num;
        if(ratings[i]>ratings[i+1]){
            num=List[i+1]+1;
        }else{
            num=1;
        }
        List[i]=fmax(num,List[i]);
        ret+=List[i];
    }
    return ret;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值