代码随想录算法训练营第三十四天丨860.柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球


860. 柠檬水找零

遇到顾客给20块的,优先拿10块的找给他。

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        change = {5: 0, 10: 0}
        for bill in bills:
            if bill == 5:
                change[5] += 1
            elif bill == 10:
                if change[5] < 1:
                    return False
                change[5] -= 1
                change[10] += 1
            else:
                if change[10] >= 1 and change[5] >= 1:
                    change[10] -= 1
                    change[5] -= 1
                elif change[5] >= 3:
                    change[5] -= 3
                else:
                    return False
        return True


406. 根据身高重建队列

我的思路:

AC了一个On^2的写法,

建一个哈希表,键为所有的身高,值为一个有序列表,以ki从小到大排序。对键值从小到大遍历,每次弹出列表尾元素,ki是多少,前面就留几个空,直到遍历完所有的元素。

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        n = len(people)
        ht = collections.defaultdict(list)
        pos = [x for x in range(n)]
        res = [None] * n
        people.sort()
        for person in people:
            ht[person[0]].append(person)
        for i in range(n):
            count = 0
            height = people[i][0]
            rank = ht[height].pop()[1]
            res[pos[rank]] = [height, rank]
            del pos[rank]
        return res

优化:

啊其实思路大概是对的了,哈希表套栈不是必要的,因为可以通过匿名函数实现身高升序、ki降序排序:

people.sort(key=lambda x:(x[0],-x[1]))

然后后续留空其实也是不必要的,可以用insert方法插值;我的方法是从低到高,把矮的按照前面有几个比他高的放到对应的位置。如果从高到低排序,先把高放下来,后面放矮的就是按照他的k值来放,矮的k只相对于前面已经放下的高的,所以从高到低放;相同高度就看k值,先放k小的,再放k大的,可以保证前面的是大于等于自己高度的。

代码:

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        people.sort(key=lambda x:(-x[0], x[1]))
        res = []
        for person in people:
            res.insert(person[1], person)
        return res

就换了个排序顺序就差了这么多代码量,真的好壮观!!

452. 用最少数量的箭引爆气球

我的方法:

先排序,起始点和终点都是升序,然后对每一个point,计算他和之前所有的交集,如果某处没有交集了,就要多打一支箭,把交集置为新的point。

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        arrows = 1
        points.sort()
        inter = points[0]
        print(points)
        for point in points:
            if point[0] > inter[1]:
                inter = point
                arrows += 1
            else:
                inter[0] = max(inter[0], point[0])
                inter[1] = min(inter[1], point[1])
        return arrows

优化:

思路大概是一样的,其实用不着每次记录一个交集,只要记录边界即可。按照end升序排序,记录end,从第一个point开始,point的start如果小于等于记录的end,那么从start射一箭必可以引爆前面所有的气球;如果start大于end了,把end置为新的point的end,多加一枝箭。

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        arrows = 1
        points.sort(key=lambda x: x[1])
        end = points[0][1]
        for i_start, i_end in points:
            if i_start > end:
                end = i_end
                arrows += 1
        return arrows

我的原始方法虽然逻辑上正确,但在处理每个气球时,尝试通过更新交集区间来最大程度地减少所需的箭数。这一步虽然在理论上能够为每次射箭找到一个最优的射击点,但实际上却增加了计算复杂度。题解方法提供了一个更为高效的视角,它通过将气球按照结束坐标进行排序,确保了我们总是在可能的最早点射出箭来引爆气球。在这个方法中,只有当遇到一个新的气球,且这个气球的起始坐标超过了当前箭能覆盖的最远距离时,才会增加箭的数量。这样的处理不仅简化了逻辑,还显著减少了计算量,因为它避免了不必要的每次交集更新,而仅在必要时更新箭的射击范围。

今日总结:

全AC了,但第二三题跟题解比起来都在运行速度上有所欠缺,思路仍然不是十分清晰,看到题解会有豁然开朗的感觉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值