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
posted @   haohaoscnblogs  阅读(16)  评论(0)    收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示