代码随想录算法训练营第三十四天|1005. K次取反后最大化的数组和,134. 加油站,135. 分发糖果
1005. K次取反后最大化的数组和
题目链接:K次取反后最大化的数组和
没用贪心,用的分类和递归
非贪心
class Solution:
def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
pos = []
neg = []
for i in range(len(nums)):
if nums[i] < 0 :
neg.append(nums[i])
else:
pos.append(nums[i])
pos.sort()
neg.sort()
if neg == []:
if k % 2 == 0:
return sum(nums)
else:
return sum(nums)-2*pos[0]
else:
if len(neg) < k:
for i in range(len(nums)):
if nums[i] < 0:
nums[i] = -nums[i]
return self.largestSumAfterKNegations(nums,(k-len(neg)))
else:
for i in range(k):
neg[i] = -neg[i]
return sum(pos)+sum(neg)
贪心
贪心算法是按照绝对值排序,如果把负数从绝对值大到小改正,知道k次数用完,如果没用完就找绝对值最小的数消耗完。
class Solution(object):
def largestSumAfterKNegations(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
nums = sorted(nums, key=abs, reverse=True)
for i in range(len(nums)):
if k > 0 and nums[i] < 0:
nums[i] *= -1
k -= 1
while k > 0:
nums[-1] *= -1
k-=1
return sum(nums)
134. 加油站
题目链接:加油站
暴力解法
不出意外,超时了,错在33 / 39。
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
for i in range(len(gas)):
#print("i",i)
j = 0
st = list(range(i,len(gas))) + list(range(i))
total = gas[st[j]]
while j < (len(gas)-1):
#print("j",j)
#print(total,cost[st[j]])
if total<cost[st[j]]:
break
else:
total -= cost[st[j]]
total += gas[st[j+1]]
j+=1
if j == (len(gas)-1) and total >= cost[st[-1]]:
return i
return -1
贪心算法
这里的逻辑是,如果一天的剩余油量加起来不是0的话就完全不够跑这一圈。
如果累计剩余变成了负数,那么我们就从curstate的下一个重新开始计数。
这样遍历完的start,要么是真正的答案,要么就是-1。
- 为什么不在前面,假设现在在j,我觉得在i<j的位置,那么就是说,我觉得i到j之间的sum一定是正的,但是因为现在到start换到j了,就意味着到j的curstate是负的,那么由于到i的curstate加上i到j之间的sum等于到j的curstate,那么到i的curstate一定是负的,所以i其实已经是过start了,现在到j就说明i不行。
- 为什么不在后面,因为是遍历到底的,一旦不行就换,遍历到最后的一定是最后一个可以的。
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
start = 0
curSum = 0
totalSum = 0
for i in range(len(gas)):
print(curSum)
print(totalSum) #这里是判断整个数组能不能行的
curSum += gas[i] - cost[i]
totalSum += gas[i] - cost[i]
if curSum < 0:
curSum = 0
start = i + 1
if totalSum < 0: return -1
return start
135. 分发糖果
题目链接:分发糖果
隐约想到一点,左边开始给小朋友糖果的情况和右边开始给小朋友糖果的情况分开统计,最后选大的那个加起来就可以。
注意就是假设从左边开始看,如果右边的孩子比有左边,那么左边的孩子还是一颗糖,而不是右边的孩子减一。
class Solution:
def candy(self, ratings: List[int]) -> int:
candy1 = [1]*len(ratings)
candy2 = [1]*len(ratings)
for i in range(1,len(ratings)):
if ratings[i] > ratings[i-1]:
candy1[i] = candy1[i-1]+1
for i in range(-2,-(len(ratings)+1),-1):
if ratings[i] > ratings[i+1]:
candy2[i] = candy2[i+1]+1
s = 0
for i in range(len(candy1)):
s += max(candy1[i], candy2[i])
return s