代码随想录第35天|860. 柠檬水找零、406. 根据身高重建队列、452. 用最少数量的箭引爆气球

108 阅读3分钟

860. 柠檬水找零

1. first idea

就模拟找零钱就可以。 但是要注意一下顺序(有用例没过,所以才想到)。

对于20的bill,我们应该优先找零10+5,而不是5+5+5. 不然5容易不够用。

所以贪心的关键是每次找零优先找最大面额的零钱。

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        cash_dict = {}
        for bill in bills:
            # 先试试能不能找开
            
            if bill == 20:
                if  (cash_dict.get(5, 0) >= 1) and (cash_dict.get(10, 0) >= 1):
                    cash_dict[bill] = cash_dict.get(bill, 0) + 1
                    cash_dict[5] = cash_dict[5] - 1
                    cash_dict[10] = cash_dict[10] - 1
                elif cash_dict.get(5, 0) >= 3:
                    # 如果可以就找开
                    cash_dict[bill] = cash_dict.get(bill, 0) + 1
                    cash_dict[5] = cash_dict[5] - 3
                else:
                    print(cash_dict)
                    return False
            if bill == 10:
                if cash_dict.get(5, 0) >= 1:
                    cash_dict[bill] = cash_dict.get(bill, 0) + 1
                    cash_dict[5] = cash_dict[5] - 1
                else:
                    print(cash_dict)
                    return False
            if bill == 5:
                cash_dict[bill] = cash_dict.get(5, 0) + 1
        return True

406. 根据身高重建队列(理解起来比较难)

1. doc reading

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        # 身高由高到低排序
        people.sort(key=lambda x: (-x[0], x[1]))
        queue = []
        for idx in range(len(people)):
            person_idx = people[idx][1]
            queue.insert(person_idx, people[idx])
        return queue
            

首先是要按照两级排序:

  1. 身高h降序,
  2. 前面比它高的个数k升序。

得到一个有序数组。

这个有序数组按照k进行插入,如果两个元素k相等,那么身高矮的应该排在身高较高的左侧,这样才能让矮个子的k满足。

而直接根据k将当前person插入结果队列恰好能满足这一要求。

因为如果结果队列长度还没超过k,那么这个person肯定插在了队尾,而哪个person插在队尾是受到之前sort影响的。

总结一下就是,矮个子排在哪都对高个子没有影响,但是高个子排在矮个子前面就会造成影响。所以,矮个子要主动选择位置。

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

1. first idea

射每一个气球的右侧边界, 每射中一个气球,就将这个气球抹去。

局部最优:只要气球重叠就一起射 全局最优:所有气球都爆掉时射箭次数最少。

能做到一起射气球,只有两种方法:

  1. 要么从左向右遍历,找每个气球的最小右边界;
  2. 要么从右向左遍历,找每个气球的最大左边界。

否则会率先将重叠的气球中突出的单个区域对应的气球射爆,而非重叠起来。

image.png

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        # 先搞个优先队列吧,根据每个点的第二个坐标值对点进行排序。
        points.sort(key=lambda x: x[1])
        
        count_int = 0
        while points:
            right_border = points[0][1]
            points = points[1:]
            count_int += 1
            while points and (points[0][0] <= right_border <= points[0][1]):
                    points = points[1:]
        return count_int

超出时限。

doc reading

class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        # 先搞个优先队列吧,根据每个点的第二个坐标值对点进行排序。
        points.sort(key=lambda x: x[1])
        
        count_int = 1
        for idx in range(1, len(points)):
            if points[idx][0] > points[idx - 1][1]:
                count_int += 1
            else:
                points[idx][1] = min(points[idx][1], points[idx - 1][1])
        return count_int

不需要真的删除,而是顺次遍历后,只要重叠,就将新的右边界更新为重叠的几个气球中最小右边界。