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)