1005. Maximize Sum Of Array After K Negations
贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
class Solution:
def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
nums.sort(key=abs, reverse=True) # 数组按绝对值从大到小排序
for i in range(len(nums)):
if nums[i] < 0 and k != 0:
nums[i] = -1 * nums[i]
k -= 1
if k > 0: #还可以调整,这时都是正数,取最小的正数
if k % 2 != 0: # 还有奇数次就需要要最小的正数变负
nums[-1] = -1 * nums[-1]
return sum(nums)
134. Gas Station
暴力(超时)
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
for i in range(len(gas)):
index = (i + 1) % len(gas) # 起始点i的下一站
rest = gas[i] - cost[i] # 下一站时的剩余
while index != i and rest > 0:
rest = rest + gas[index] - cost[index]
index = (index + 1) % len(gas)
# 以 i 为起点跑完一圈,若 rest >= 0,则返回起始位置
if rest >= 0 and index == i:
return i
return -1
贪心
(gas[i] - cost[i])
可以认为是每个加油站对全局的贡献值,假设可以跑通,则每个加油站的贡献值之和一定 >= 0
对于全局:if totalSum < 0: return -1
对于局部:
首先,那个可以跑通的start
点一定存在;
假设从i
出发走到j
时curSum
< 0,则说明[i, j]
都不能作为start
。因为i
走到j-1
时,curSum
还为正,加上j
处的负贡献后curSum
才 < 0,i
不可能,i+1
没了i
的正贡献更不可能走通… j
自身就是负贡献,无法作为起始点执行下一步;所以将start
设为j+1
,它有可能是start
点。
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
curSum = 0
totalSum = 0
start = 0
for i in range(len(gas)):
curSum += (gas[i] - cost[i])
totalSum += (gas[i] - cost[i])
if curSum < 0:
start = i + 1
curSum = 0
if totalSum < 0:
return -1
return start
135. Candy
采用了两次贪心的策略:
- 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
- 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。
这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。
class Solution:
def candy(self, ratings: List[int]) -> int:
candyVec = [1] * len(ratings)
# 从前往后,只和自己左边的比
for i in range(1, len(ratings)):
if ratings[i] > ratings[i - 1]:
candyVec[i] = candyVec[i - 1] + 1
# 从后往前,只和自己右边的比
for i in range(len(ratings) - 2, -1, -1):
# 取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量
# 保证第i个小孩的糖果数量即大于左边的也大于右边的
if ratings[i] > ratings[i + 1]:
candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1)
return sum(candyVec)