Leetcode| 1005. K次取反后最大化的数组和、134. 加油站、135. 分发糖果 Day34

本文探讨了三个编程问题的解决方案:最大数组和优化(MaximizeSumOfArrayAfterKNegations)、加油站路径选择(GasStation)和糖果分配(Candy)。通过贪心策略和暴力搜索方法,展示了如何在不同场景中寻找局部和全局最优解。
摘要由CSDN通过智能技术生成

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出发走到jcurSum < 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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值