2024.07.30 代码随想录 | 贪心算法

45.跳跃游戏 II*

这个与跳跃游戏的区别在于,对每一个cover,我们在这个cover内每一个i里面寻找下一个最大的cover,直到最大的才更新。

而跳跃游戏解法是,对每一个cover,我们遍历这个cover内的i同时更新cover,直到cover能覆盖整个nums

例子:

# [7,0,9,6,9,6,1,7,9,0,1,2,9,0,3,1]

跳跃游戏

#        i: 0 1 2 3 4 5 6 7 8

#cover: 7 7 11 11 13 13 13 14 17 > 15 end

跳跃游戏二:

i,   (i,cover+1), cover, count

0,  (0, 1),   7,  2

0,  (0, 8), 14, 3

0,   (7, 15), 17>15, return 3

class Solution:
    def jump(self, nums: List[int]) -> int:
        if len(nums) == 1:
            return 0
        i, cover = 0, 0
        count = 1
        while i <= cover:
            for i in range(i, cover + 1):
                cover = max(i + nums[i], cover)
                if cover >= len(nums) - 1:
                    return count
            count += 1
        

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

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

  • 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

我的解法:

class Solution:
    def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:
        nums.sort()
        for i in range(len(nums)):
            if nums[i] < 0 and k > 0:
                nums[i] = -nums[i]
                k -= 1
            elif nums[i] >= 0:
                break
        if k % 2 == 1 and nums[i] < nums[i-1]:
            nums[i] = -nums[i]
        elif k % 2 == 1 and nums[i] >= nums[i-1]:
            nums[i-1] = -nums[i-1]
        return sum(nums)

随想录解法:
用到了lambda函数,按绝对值从大到小排序,A.sort(key=lambda x: abs(x), reverse=True)

class Solution:
    def largestSumAfterKNegations(self, A: List[int], K: int) -> int:
        A.sort(key=lambda x: abs(x), reverse=True)  # 第一步:按照绝对值降序排序数组A

        for i in range(len(A)):  # 第二步:执行K次取反操作
            if A[i] < 0 and K > 0:
                A[i] *= -1
                K -= 1

        if K % 2 == 1:  # 第三步:如果K还有剩余次数,将绝对值最小的元素取反
            A[-1] *= -1

        result = sum(A)  # 第四步:计算数组A的元素和
        return result

134. 加油站*

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

这一题的重点就是:当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        cur_gas = 0
        total_gas = 0
        # 注意起始的start为0 eg: [3,1,1] [1,2,2], cur_gas 一直大于等于零,start应该是0
        start = 0
        for i in range(len(gas)):
            cur_gas += gas[i] - cost[i]
            total_gas += gas[i] - cost[i]
            if cur_gas < 0:
                start = i + 1
                cur_gas = 0
        if total_gas < 0:
            return -1
        else:
            return start

135. 分发糖果*

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

我的解答:不对,如果出现分数连续递减的情况就不对了

class Solution:
    def candy(self, ratings: List[int]) -> int:
        # [1,3,2,2,1]
        #  1,2,1,2,1
        # [1,2,87,87,87,2,1]
        #  1, 2, 3, 1, 3,2,1
        n = len(ratings)
        if n == 1:
            return 1
        pre_candy = 0
        pre_candy = 1 if ratings[0] <= ratings[1] else 2
        candy = pre_candy
        for i in range(1, n):
            if ratings[i] > ratings[i-1]:
                candy += pre_candy + 1
                pre_candy += 1
            else:
                if i + 1 <= n - 1 and ratings[i] > ratings[i+1]:
                    candy += 2
                    pre_candy = 2
                elif pre_candy > 1:
                    candy += 1
                    pre_candy = 1
                else:
                    candy += pre_candy
        
        return candy

随想录解法:
 

class Solution:
    def candy(self, ratings: List[int]) -> int:
        # [1,2,87,87,87,2,1]
        # 从左向右 只考虑左边:1,2,3,1,1,1,1
        # 从右到左 只考虑右边:1,1,1,1,3,2,1
        # 取相对大, 得到结果:1,2,3,1,3,2,1
        n = len(ratings)
        candy = [1] * n
        for i in range(1, n):
            if ratings[i] > ratings[i - 1]:
                candy[i] = candy[i-1] + 1
        for i in range(n-2, -1, -1):
            if ratings[i] > ratings[i+1]:
                candy[i] = max(candy[i+1] + 1, candy[i])
        return sum(candy)

860.柠檬水找零

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

我的解法:

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        change_count = {'5': 0, '10': 0}
        # [5,5,10,20,5,5,5,5,5,5,5,5,5,10,5,5,20,5,20,5]
        for i in range(len(bills)):
            if bills[i] == 10:
                change_count['10'] += 1
                change_count['5'] -= 1
            elif bills[i] == 20:
                if change_count['10'] > 0:
                    change_count['10'] -= 1
                    change_count['5'] -= 1
                else:
                    change_count['5'] -= 3
            else:
                change_count['5'] += 1
            if change_count['5'] < 0 or change_count['10'] < 0:
                return False
        return True

 随想录解法:思路一样不过具体实现方案略有不同

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        five = 0
        ten = 0
        twenty = 0
        
        for bill in bills:
            # 情况一:收到5美元
            if bill == 5:
                five += 1
            
            # 情况二:收到10美元
            if bill == 10:
                if five <= 0:
                    return False
                ten += 1
                five -= 1
            
            # 情况三:收到20美元
            if bill == 20:
                # 先尝试使用10美元和5美元找零
                if five > 0 and ten > 0:
                    five -= 1
                    ten -= 1
                    #twenty += 1
                # 如果无法使用10美元找零,则尝试使用三张5美元找零
                elif five >= 3:
                    five -= 3
                    #twenty += 1
                else:
                    return False
        
        return True

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值