代码随想录算法训练营day34|leetcode1004/134/135

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

力扣

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

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

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

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

 思路:既然是要取反 那么可以考虑到绝对值的方向上去,先把数组按照绝对值大小 从小到大排序。其次:对数组进行遍历,遇到负数就*-1 变为正数。

让整个数组中绝对值最大的负数 变为正数 可以达到数组和最大

如果说将数组中进行反转之后,数字 每个都>0了,但是k还没有用完怎么办

那就反转绝对值最小的正整数 把k用完

比如 5,1,3。排序后为5,3,1

这里如果k=1,那就把1反转为 -1 最大值为7

反转1 得到-1 比 反转5得到的-5 大多了。所以是对最后一位数字 进行反转

总结就是:局部最优 推出全局最优  贪心算法

代码:

def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
        ans = sorted(nums,key=abs,reverse=True)
        for i in range(len(ans)):
            if k >0 and ans[i] <0:
                ans[i]*=-1
                k-=1 
        if k > 0:
            ans[-1] *= (-1)**k
        return sum(ans)

Leetcode134加油站

力扣

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

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

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

说实话,一开始是绕进去 给直接绕死了。

讲讲思路:首先设置一个cursum记录当前消耗的油量,创建一个totalsum记录消耗的总油量。如果到最后,总油量>0,那么就说明 当前从当前加油站出发是可以进行一圈的循环的。如果是<0的话,就直接返回-1.

一开始 我们的cursum可以写成 当前的gas[i] 也就是获取到的油量 - cost[i]行驶之后消耗的油量  = 我们的剩余油量,如果cursum<0了,就说明从当前加油站出发是不太理想的一个位置,既然我们想要保证车子可以完整的循环一周,那么局部最优就是 从当前加油站出发到下一个 都有足够的油量,后面也是一样,也就是两个加油站之间, 都要保证有足够的油量可以去使用。如果不行的话,那就不从当前加油站出发,所以start = i+1。直接跳到下一个加油站,然后重置cursum=0。但是totalsum不用重置

为什么?

因为totalsum是记录整个循环周期下来你的剩余油量有多少,既然能完整的走完一圈,那么油量多少还是有剩余的。所以不用重置。

代码

def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        #开始的时候油箱=0
        start = 0
        #当前的剩余汽油
        curSum = 0
        #最后的总汽油
        totalSum = 0
        for i in range(len(gas)):
            curSum += gas[i] - cost[i]
            totalSum += gas[i] - cost[i]
            #如果一开始从这个加油站到下一个加油站 剩余邮箱已经<0了
            #那么就说明不能以当前的加油站为起点 并且把当前消耗的油量重置=0
            if curSum < 0:
                curSum = 0
                start = i + 1
#为什么不把totalsum重置为0 呢
#因为这是从当前加油站出发之后 消耗的油量 是回不来的 
#消耗了就消耗了  只要判断最后的油量是不是大于0 就行
        if totalSum < 0: return -1
        return start

 Leetcode135分发糖果  

力扣

 思路:分两个情况去判断,一个是先比较左边孩子评分>右孩子评分,第二个是右孩子评分>左孩子。

首先从右孩子评分>左孩子评分开始,如果rating[i] > rating[i-1],那么我们的res[I]就应该等于res[i-1]+1。也就是右边评分大于左边,那么我们右边的孩子就要比左边孩子的糖果数量多1个。所以是raitings[i-1]+1.(这里是从前向后遍历)

res是初始化为[1]*len(ratings),首先每个孩子手中至少有一个糖果。

然后是左孩子>右孩子的情况,这里注意!这里需要从后向前遍历!!

为什么不能用从前往后呢?

因为如果从前向后遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果了。

这里给大家放个图 简单理解一下

从左向右: 

整体:

 

代码:

def candy(self, ratings: List[int]) -> int:
        """思路
        分开判断 
        左孩子的评分>右孩子(从后向前遍历)
        中间孩子的话 就取两边
        右孩子的评分>左孩子(从前往后遍历)"""

        res = [1] * len(ratings)
        for i in range(1,len(ratings)):
            #从左向右 比较右孩子的评分大于左孩子的情况
            if ratings[i] > ratings[i-1]:
                res[i] = res[i-1] + 1 
            #从右向左 比较左孩子评分大于右孩子的情况
        for j in range(len(ratings)-2,-1,-1):
            if ratings[j] > ratings[j+1]:
                res[j] = max(res[j],res[j+1]+1)
        return sum(res)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值