算法练习Day27 (Leetcode/Python-贪心算法)

452. Minimum Number of Arrows to Burst Balloons

There are some spherical balloons taped onto a flat wall that represents the XY-plane. The balloons are represented as a 2D integer array points where points[i] = [xstart, xend] denotes a balloon whose horizontal diameter stretches between xstart and xend. You do not know the exact y-coordinates of the balloons.

Arrows can be shot up directly vertically (in the positive y-direction) from different points along the x-axis. A balloon with xstart and xend is burst by an arrow shot at x if xstart <= x <= xend. There is no limit to the number of arrows that can be shot. A shot arrow keeps traveling up infinitely, bursting any balloons in its path.

Given the array points, return the minimum number of arrows that must be shot to burst all balloons.

Example 1:

复制代码
Input: points = [[10,16],[2,8],[1,6],[7,12]]
Output: 2
Explanation: The balloons can be burst by 2 arrows:
- Shoot an arrow at x = 6, bursting the balloons [2,8] and [1,6].
- Shoot an arrow at x = 11, bursting the balloons [10,16] and [7,12].

思路:最少多少剑射穿气球。

先对气球按照一边的大小进行排序。若按照左边界,那么当前气球的左边界如果大于之前累积的气球的右边界,就必须得加一支箭才可以射穿当前气球了。

以这个思路,更详细分析就是要记录当前累计气球的交集,也就是在哪个范围内当前箭可射穿当前累计的所有气球。若气球1是[2,5], 气球2是[3,6], 那么这个交集的区间是[3,5], 左边界是3,右边界是5,如果新来的气球的左边界大于了5,那么就无法用同一支箭射穿了。这种情况下,写法上可以选择更新原气球数组,每次都把当前气球i的左右边界更新为当前箭可射穿的左右边界,如果下一个气球i依然可以被同一支箭射穿,那就继续更新下一个气球的右边界,否则就不更新了,算是新一支箭的左右边界。另一种不更新原数组的写法就是记录当前箭的左右边界。

不过注意了,更简化的算法是只更新右边界就可以了,左边界的更新是冗余的。因为排过序,新的左边界肯定大于旧的左边界,所以只要新的左边界小于旧的右边界,左边界就一定是落在原来区间的,反之则不然。

另外要注意的一点是xstart <= x <= xend就可以射穿,这里是闭区间,所以判断是否需要一支新箭时,取的是右边界大于之前的左边界时才要换,而不是大于等于。

还有写法上如果涉及i-1,for循环序号就要注意从1开始。那么序号为0的情况就要特别处理,或可考虑作为初始化。

python 复制代码
class Solution(object):
    def findMinArrowShots(self, points):
        """
        :type points: List[List[int]]
        :rtype: int
        """
        """
        if len(points) == 0: return 0
        points.sort(key = lambda x: x[0])
        result = 1
        for i in range(1,len(points)):
            if points[i][0]>points[i-1][1]:
                result += 1 
            else:
                points[i][1] = min(points[i-1][1], points[i][1])
        return result
        """
        points.sort(key = lambda x:x[0])
        sl, sr = points[0][0], points[0][1] # use sl and sr to record the left and right boundary of the current interval separately.
        count = 1
        for i in points:
            if i[0] > sr: # if the left boundary of this balloons is out of current interval, we need a now arrow. 
                count += 1
                sl, sr = i[0], i[1] #注意,不仅仅是右边界要更新,左边界也是要更新的!!
            else:
                sl = max(sl, i[0]) # 不要搞错了min和max,这里要的是区间的交集不是并集
                sr = min(sr, i[1])
        return count 

406. Queue Reconstruction by Height

You are given an array of people, people, which are the attributes of some people in a queue (not necessarily in order). Each people[i] = [hi, ki] represents the ith person of height hi with exactly ki other people in front who have a height greater than or equal to hi.

Reconstruct and return the queue that is represented by the input array people. The returned queue should be formatted as an array queue, where queue[j] = [hj, kj] is the attributes of the jth person in the queue (queue[0] is the person at the front of the queue).

Example 1:

复制代码
Input: people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
Output: [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
Explanation:
Person 0 has height 5 with no other people taller or the same height in front.
Person 1 has height 7 with no other people taller or the same height in front.
Person 2 has height 5 with two persons taller or the same height in front, which is person 0 and 1.
Person 3 has height 6 with one person taller or the same height in front, which is person 1.
Person 4 has height 4 with four people taller or the same height in front, which are people 0, 1, 2, and 3.
Person 5 has height 7 with one person taller or the same height in front, which is person 1.
Hence [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] is the reconstructed queue.

思路:根据身高重建队列。有两重排序标准,第一是身高h从高到低,第二是要求前面有k个比自己高的。先按照第一重标准排序,并且这个时候对于相同的h,k小的在前面(即使在最终的排序结果中,k小的也应该在前面)。再按照第二重标准来,第一重排序中靠前的具有优先排序的资格。因为本身身低的并不继续影响前面身高高的k值了。

写法上要注意 people.sort(key=lambda x:(-x[0], x[1])) ,表示先按照x[0] 从大到小排序(通过取负数得到),x[0]相同的情况下,再考虑x[1]由小到大排序。

另外,插入的写法是 que.insert(i[1],i) 。一开始我错误地写成了que[i[1]] = i ... 这样意思就完全错了。。。

以及,一开始做这道题时,并没考虑h相同k不同的情况。这点也应该考虑周全了。

python 复制代码
class Solution(object):
    def reconstructQueue(self, people):
        """
        :type people: List[List[int]]
        :rtype: List[List[int]]
        """
        # 先按照h维度的身高顺序从高到低排序。确定第一个维度
        # lambda返回的是一个元组:当-x[0](维度h)相同时,再根据x[1](维度k)从小到大排序
        people.sort(key=lambda x:(-x[0], x[1])) 
        que = []

        # 根据每个元素的第二个维度k,贪心算法,进行插入
        # people已经排序过了:同一高度时k值小的排前面。
        for i in people:
            que.insert(i[1],i) 
        return que

860. Lemonade Change

At a lemonade stand, each lemonade costs $5. Customers are standing in a queue to buy from you and order one at a time (in the order specified by bills). Each customer will only buy one lemonade and pay with either a $5, $10, or $20 bill. You must provide the correct change to each customer so that the net transaction is that the customer pays $5.

Note that you do not have any change in hand at first.

Given an integer array bills where bills[i] is the bill the ith customer pays, return true if you can provide every customer with the correct change, or false otherwise.

Example 1:

复制代码
Input: bills = [5,5,5,10,20]
Output: true
Explanation: 
From the first 3 customers, we collect three $5 bills in order.
From the fourth customer, we collect a $10 bill and give back a $5.
From the fifth customer, we give a $10 bill and a $5 bill.
Since all customers got correct change, we output true.

思路:这道题乍一看有点复杂,列出所有可能的情况后发现其实很简单。

只需要维护三种金额的数量,5,10和20。

有如下三种情况:

  • 情况一:账单是5,直接收下。
  • 情况二:账单是10,消耗一个5,增加一个10
  • 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5

因为5可以被用来解决2、3两种情况,而10只可以解决3。所以优先花掉10,如果没有10的话再去找5救火。

python 复制代码
class Solution(object):
    def lemonadeChange(self, bills):
        """
        :type bills: List[int]
        :rtype: bool
        """
        five = 0
        ten = 0
        twenty = 0
        
        for bill in bills:
            # 情况一:收到5美元
            if bill == 5:
                five += 1
            
            # 情况二:收到10美元
            if bill == 10:
                if five <= 0:
                    return False
                ten += 1
                five -= 1
            
            # 情况三:收到20美元
            if bill == 20:
                # 先尝试使用10美元和5美元找零
                if five > 0 and ten > 0:
                    five -= 1
                    ten -= 1
                    #twenty += 1
                # 如果无法使用10美元找零,则尝试使用三张5美元找零
                elif five >= 3:
                    five -= 3
                    #twenty += 1
                else:
                    return False
        
        return True
相关推荐
白榆maple17 分钟前
(蓝桥杯C/C++)——基础算法(下)
算法
JSU_曾是此间年少21 分钟前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
咕咕吖2 小时前
对称二叉树(力扣101)
算法·leetcode·职场和发展
九圣残炎2 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
lulu_gh_yu2 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!3 小时前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚3 小时前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
为什么这亚子4 小时前
九、Go语言快速入门之map
运维·开发语言·后端·算法·云原生·golang·云计算
4 小时前
开源竞争-数据驱动成长-11/05-大专生的思考
人工智能·笔记·学习·算法·机器学习