3道题目
1005. K 次取反后最大化的数组和
134. 加油站
135. 分发糖果
解题理解
1005
看起来是道简单题,但实现完发现有个样例怎么都过不了,仔细看了题干和题解之后才意识到,k是取负的次数,之前想的是直接按从小到大排序,取前k个小于等于0的数取反就能得到最大值,所以有的样例会得到比答案更大的和。
正确思路是,按绝对值大小从大到小排序,让前k个小于0的数取反,如果不够k个,就让最小的数反复取完最后的次数。
class Solution:
def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
nums.sort(key = lambda x: abs(x), reverse = True)
for i in range(len(nums)):
if nums[i] < 0 and k > 0:
k -= 1
nums[i] *= -1
if k % 2 == 1:
nums[-1] *= -1
return sum(nums)
134
这里的贪心思想有点削峰填谷的意思,首先逐个遍历gas和cost,gas[i] - cost[i]是当天的剩油量,如果遍历完一圈,剩油量还大于0,说明从0开始就可以跑完;其次如果总油量<总消耗,那无论怎样都跑不完;最后当计算遍历两个数组后,剩油量是负数时,从gas后往前遍历,哪一站能填平这个缺口,就是开始的站点,因为只有在能填平负数的那一站开始,才能保证多跑一圈后到该站能把油量补上。
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
rest = 0
mingas = 10000000
for i in range(len(gas)):
rest += gas[i] - cost[i]
if mingas > rest:
mingas = rest
if rest < 0:
return -1
if mingas >= 0:
return 0
index = len(gas) - 1
while index > 0:
mingas += gas[index] - cost[index]
if mingas >= 0:
return index
index -= 1
135
这道题的贪心思想要分两个方向看,这种思路确实再怎么想也想不到,大致就是,先给每个孩子一个糖果,然后先从左到右看,分数更高的多分一个,相等或小于的维持1个不动,然后再从右往左看,分数更高的那个需要跟右边小于他的糖果数+1比,谁大就给分数更高的孩子。
class Solution:
def candy(self, ratings: List[int]) -> int:
candynum = [1] * len(ratings)
for i in range(1, len(ratings)):
if ratings[i] > ratings[i - 1]:
candynum[i] = candynum[i - 1] + 1
i = len(ratings) - 2
while i >= 0:
if ratings[i] > ratings[i + 1]:
candynum[i] = max(candynum[i], candynum[i + 1] + 1)
i -= 1
return sum(candynum)