一、134. 加油站
本题有点难度,不太好想,推荐大家熟悉一下方法二
代码实现
(1)定义变量current_sum用于统计每一个站点的剩余油量;变量total_sum用于统计整个的剩余油量,如果total_sum小于0,说明无论从哪里出发都无法跑完一圈; 思路是只要current_sum小于0,那么就从i+1出发,所以定义一个变量start用于记录新的起始位置。
(2)for循环遍历数组:current_sum累加每一个站点剩余的油量,也就是补充油量减去消耗油量;同时total_sum也和current_sum一样去进行统计;如果current_sum小于0,说明i之前都不适合作为起始位置,所以start更新为i+1,并且current_sum归0。
(3)for循环结束后,total_sum小于0,那么返回-1;否则就返回start。
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
start = 0
cur_sum = 0
total_sum = 0
for i in range(len(gas)):
cur_sum += (gas[i]-cost[i])
total_sum += (gas[i]-cost[i])
if cur_sum < 0:
start = i+1
cur_sum = 0
if total_sum < 0:
return -1
return start
二、135. 分发糖果
本题涉及到一个思想,就是想处理好一边再处理另一边,不要两边想着一起兼顾,后面还会有题目用到这个思路
1. 解题思路
当既要比较左边又要比较右边的情况下,不能两边同时比较,因为会混淆,所以我们采用的方法是两边分开进行比较。
(1)只看右边小孩比左边小孩得分高的情况:在代码上表现为当右边孩子比左边孩子高,也就是rating[ i ] > rating[ i-1 ],那么右边孩子的糖果数就是左边孩子糖果数加1,也就是candy[ i ]等于candy[ i - 1]+1。
(2)左边小孩比右边小孩得分高的情况:此时需要从后向前遍历,因为这样才可以用到(1)的结果,否则比较会失效。如果左边小孩比右边小孩得分高的话,即rating[ i ]大于rating[ i+1 ],也就是candy[ i ]更新为要candy[ i + 1] +1,但是由于(1)已经比较过右孩子比左孩子高的情况了,那么candy[ i ]应该更新为 二者较大的那个数,也就是如果 i 比左右孩子都大,那么它应该取较大的那个值才能保证比较是正确的。
2. 代码实现
(1)定义candy数组,并且默认每个初始值均为1,也就是每个小孩至少得到1个糖果。
(2)首先比较右小孩比左小孩得分高的情况:for循环rating数组,注意 i 从1开始,因为 i 需要和 i-1 进行比较。当右边孩子比左边孩子高,也就是rating[ i ] > rating[ i-1 ],那么右边孩子的糖果数就是左边孩子糖果数加1,也就是candy[ i ]等于candy[ i - 1]+1。
(3)其次,倒序遍历,在(2)的基础上比较左边小孩比右边小孩得分高的情况:由于倒序遍历,所以 i 从len( rating )-2开始,因为需要比较 i 和 i+1。如果左边小孩比右边小孩得分高的话,即rating[ i ]大于rating[ i+1 ],也就是candy[ i ]更新为要candy[ i + 1] +1,但是由于(1)已经比较过右孩子比左孩子高的情况了,那么candy[ i ]应该更新为 二者较大的那个数。
(4)遍历整个更新后的candy数组,定义result变量进行累加,最终返回结果。
class Solution:
def candy(self, ratings: List[int]) -> int:
result = 0
candy = [1] * len(ratings)
for i in range(1, len(ratings)):
if ratings[i] > ratings[i-1]:
candy[i] = candy[i-1]+1
for i in range(len(ratings)-2, -1, -1):
if ratings[i] > ratings[i+1]:
candy[i] = max(candy[i], candy[i+1]+1)
for i in range(len(candy)):
result += candy[i]
return result
三、860.柠檬水找零
本题看上好像挺难,其实很简单,大家先尝试自己做一做。
1. 解题思路
可以发现,面额为5,无需找零;面额为10,找零只能是5;面额为20找零有两种策略,一是10加5,二是3张5。所以按照贪心策略,我们尽量保留较多的5,找零更加有优势,所以需要先消耗10。
2. 代码实现
(1)定义3个变量five、ten、twenty均初始化为0,由于记录目前手里对应面额钞票的数量。
(2)从头到尾遍历账单数组:
情况1:遇到账单为5,那么five直接加1;
情况2:如果收到账单为10,那么要对其进行找零:判断手上是否有5,如果没有5,就说明无法进行找零,只能return False,如果手上有5,那么可以对其找零,那么ten加1,five减1;
情况3:如果收到20,那么需要优先选择10和5找零,如果ten和five都大于0,说明可以进行找零,那么ten和five均自减1,twenty则加1。如果策略1(10+5)不满足,就使用策略2(3张5元)进行找零:five-3,twenty+1。如果两个策略都不行,只能return False。
(3)循环完全结束,那么return True。
class Solution:
def lemonadeChange(self, bills: List[int]) -> bool:
five = 0
ten = 0
twenty = 0
for i in range(len(bills)):
if bills[i] == 5:
five += 1
if bills[i] == 10:
if five > 0:
five -= 1
ten += 1
else:
return False
if bills[i] == 20:
if five > 0 and ten > 0:
five -= 1
ten -= 1
twenty += 1
elif five >= 3:
five -= 3
twenty += 1
else:
return False
return True
四、406.根据身高重建队列
本题有点难度,和分发糖果类似,不要两头兼顾,处理好一边再处理另一边。
1. 解题思路
首先按照身高进行从高到低排序,然后再比较k,按k从小到大排序,如果k小于前面的k,那么直接将这个元素向前插入即可,不会影响前面身高的k。因为如果你一开始就比前面的身高要高的话,那么一开始排序就会排在前面,然而并不是,所以向前插入时也不会影响前面身高对应的k。
2. 代码实现
class Solution:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
people.sort(key = lambda x:(-x[0],x[1]))
p = []
for i in people:
p.insert(i[1], i)
return p