Day29 贪心算法part3
任务
134. 加油站
在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
思路
暴力解法考虑循环列表的遍历,利用while和取余操作。
贪心法:只要之前累计的sum为负数,就从下一个开始重新累计,用start标记新开始的位置。另一个总的累计变量判断整体的利润(加油-损耗)是否大于等于0,退出循环后,根据整体利润判断返回-1还是返回start。
注意为什么不会在更新start之前的某个索引为起点的情况,因为我们是顺序遍历,之前如果遇到了所说的情况,在遍历到那个节点的时候一定已经更新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. 分发糖果
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
思路
一次性遍历无法解决原因是,主要是在candies[i-1] > candies[i]这种情况,我们不知道后面有几个连续小(或等)的值,也就无法去给遍历到的节点赋值。因此使用将规则分为两个的做法。
从左到右,判断右边大的情况,然后从右到左,判断左边大的情况,注意第二次遍历时需要综合左右满足题意。说起来简单,实际上很难想到。但是提供了一种思路,即两边分开考虑。
class Solution: def candy(self, ratings: List[int]) -> int: candies = [1] * len(ratings) for i in range(1,len(ratings)): if ratings[i] > ratings[i-1]: # 从前往后,判断右大 candies[i] = candies[i-1] +1 for i in range(len(ratings)-2,-1,-1): #注意这里的写法与从前到后保持一致,即第一个i实际是倒数第二个,i+1是最后一个 if ratings[i+1] < ratings[i]: # 从后往前,判断左大 candies[i] = max(candies[i],candies[i+1]+1) sum = 0 for elem in candies: print(elem) sum += elem return sum
860. 柠檬水找零
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
思路
遍历数组,根据每种情况分别去实际模拟,注意20块时,有找一个10块和一个5块,以及三个5块两种找法,优先第一种找法,因为5块更通用,除了能够满足给20块找零,还能满足给10块找零。
class Solution: def lemonadeChange(self, bills: List[int]) -> bool: five = 0 ten = 0 for bill in bills: if bill == 5: five += 1 elif bill == 10: if five >= 1: ten+=1 five-=1 else: return False elif bill ==20: if ten >= 1 and five >=1: ten-=1 five-=1 elif five >= 3: five-=3 else: return False return True
406. 根据身高重建队列
假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
思路
根据身高先排序(从大到小),相同情况再根据k排序(从小到大), 然后在结果列表中将它们添加到相应的位置。
这里隐含了按规则排好序后,插入的索引一定在合法范围内,比如已经落位了n个数,则插入的索引一定在[0,n]中
class Solution: def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]: people.sort(key= lambda x:(-x[0],x[1])) #先按照高度从大到小排,高度相同情况下按照k从小到大排 result = [] for person in people: result.insert(person[1],person) return result
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合终身会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步