1005. K 次取反后最大化的数组和
贪心算法
- 贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。局部最优可以推出全局最优。
- 那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让 数组和 达到最大。那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个 数组和 达到最大。
class Solution:
def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
# sort nums by absolute value of element descendingly
sorted_list = sorted(nums, key=abs, reverse=True)
for i in range(len(sorted_list)):
if k > 0 and sorted_list[i] < 0:
sorted_list[i] *= -1
k -= 1
if k > 0:
sorted_list[-1] *= (-1) ** k
return sum(sorted_list)
134. 加油站
贪心
- 首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈
- i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,起始位置从i+1算起,再从0计算curSum。(从i+1的位置开始寻找下一个rest大于0的index)
- 那么局部最优:当前累加rest[j]的和curSum一旦小于0,起始位置至少要是j+1,因为从j开始一定不行。全局最优:找到可以跑一圈的起始位置。
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
remaining_gas = [ gas[i] - cost[i] for i in range(len(gas)) ]
if sum(remaining_gas) < 0:
return -1
cur_sum = 0
start = 0
for i in range(len(gas)):
cur_sum += remaining_gas[i]
if cur_sum < 0:
cur_sum = 0
start = i + 1
return start
135. 分发糖果
贪心
-
这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。先确定右边评分大于左边的情况(也就是从前向后遍历)
- 此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
- 局部最优可以推出全局最优。
-
再确定左孩子大于右孩子的情况(从后向前遍历)
- 因为如果从前向后遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果了。所以确定左孩子大于右孩子的情况一定要从后向前遍历!
- 如果 ratings[i] > ratings[i + 1],此时candyVec[i](第i个小孩的糖果数量)就有两个选择了,一个是candyVec[i + 1] + 1(从右边这个加1得到的糖果数量),一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
- 那么又要贪心了,局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量即大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
- 局部最优可以推出全局最优。
-
那么本题我采用了两次贪心的策略:
- 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
- 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。
这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。
class Solution:
def candy(self, ratings: List[int]) -> int:
candy_res = [1] * len(ratings)
# right > left
for i in range(len(ratings) - 1):
if ratings[i] < ratings[i+1]:
candy_res[i+1] = candy_res[i] + 1
# right < left
for i in range(len(ratings) - 2, -1, -1):
if ratings[i] > ratings[i+1]:
# have to meet two constraints
candy_res[i] = max(candy_res[i+1] + 1, candy_res[i])
return sum(candy_res)