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

1005.K次取反后最大化的数组和

1.题目
给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。(我们可以多次选择同一个索引 i。)以这种方式修改数组后,返回数组可能的最大和。

2.实现
解题思路易想,但很难想全所有情况,问题在于:
在思考时取定目标,如本题就是让尽可能小的数去变号,涉及到有无负数,负数的个数与k相比,是否含有0;但如何进行顺序判断是优化解题步骤的重要方法;
有了思路之后要打好框架

class Solution:
    def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
        # 数组从小到大排序
        nums = sorted(nums)
        n = len(nums)
        i = 0
        while k > 0 and i < n:
            if nums[i] < 0:
                nums[i] = -nums[i]
                i += 1
            elif nums[i] == 0:
                break
            else:
                if i > 0 and nums[i] >= nums[i - 1]:  # 不能只看原来数组,改了之后是否会影响
                    nums[i - 1] = ((-1)**k)*nums[i - 1]
                else:
                    nums[i] = ((-1)**k)*nums[i]
                break
            k -= 1
        if i == n and k > 0: # 当有多个跳出条件时,考虑多个条件跳出时的情况
            if nums[n - 1] < 0:
                nums[i] = ((-1)**k)*nums[i]
            if nums[n - 1] > 0:
                if nums[n - 1] <= nums[n - 2]:
                    nums[n - 1] = ((-1)**k)*nums[n - 1]
                else:
                    nums[n - 2] = ((-1)**k)*nums[n - 2]
        return sum(nums)

3.文章讲解
巧妙思路:按绝对值大小进行降序排序,再遍历数组将负值反号,再讨论负值和k的大小从而牺牲最后一个(可能为0的数)

134. 加油站

1.题目
在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

2.实现:
困难点:
超出时间限制,我居然连暴力都没过,想法没优化前,建议对比和暴力算法的复杂度,如果没有得到提升还不如用暴力

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        # 2 3 4 2 3 4  [-1, -1, 1   -1, -1, 1]  选择大于0的家有点出发,且保证子数组的和都是>0
        # 3 4 3 3 4 3
        # 1 2 3 4 5   [-2 -2 -2 3 3 -2 -2 -2 3 3]
        # 3 4 5 1 2
        n = len(gas)
        tmp = 0
        total_sum = 0
        index = 0
        for i in range(n):
            diff = gas[i] - cost[i]
            tmp += diff
            total_sum += diff
            if tmp < 0:
                index = i + 1
                tmp = 0
                # print("j的值:", j, n + i)
        if total_sum < 0: return -1
        return index

3.文章讲解
亮点:
仔细想想自己的解法,发现会一直计算从每个点开始的耗油总量,且需保证每个子数组的耗油总量大于0,但我的思路是会重复计算,然而题解就分了两次判断
1)总耗油量一次计算且必须>0,通过遍历所有数组即得
2)每段耗油量>0只是为了确定从哪里出发,所以遍历数组时只需不断改变起点即可!

135. 分发糖果

1.题目
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻的孩子中,评分高的孩子必须获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?

2.实现
思路1:新建了candies数组,但超出时间限制,此时极端情况可能O(n**2)的时间复杂度
思路2:在1的基础上,找准目标,要求最大和于是舍弃更新数组再去求和,而是记录res并返回,因为此时糖果分配是有规律可循的,根据评分的变化,具体看代码实现

class Solution:
    def candy(self, ratings: List[int]) -> int:
        n = len(ratings)
        # 去统计res即可
        res = 1
        state = 1
        i = 1
        while i < n:
            # 升的情况
            if ratings[i] > ratings[i - 1]:
                state += 1
                res += state
                i += 1
            # 相等时
            elif ratings[i] == ratings[i - 1]:
                state = 1
                res += state
                i += 1
            # 讨论连减
            else:
                cnt = 0
                while i < n and ratings[i] < ratings[i - 1]:
                    i += 1
                    cnt += 1
                res += int((cnt + 1)* cnt / 2)
                if state == cnt:
                    res += 1
                elif state < cnt:
                    res += (cnt - state + 1)
                state = 1
                if i == n:
                    return res
        return res

实现时遇到的一个问题:
更改for循环i时,并不能改变循环次数,for循环的循环机制是range作为迭代器,每循环一次就把值赋值给i,所以循环体内改变i的值,对循环次数无影响

3.文章讲解
思路:两个方向,对于右>左即rating[i] > rating[i - 1]的情况,只需满足candies[i] = candies[i - 1] + 1,从前往后遍历
但还需考虑左>右时是否糖果分配妥当,要根据nums[i+1]调整nums[i],且为了保留上一次遍历的结果需从后往前遍历,处理nums[i]也有了新技巧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值