代码随想录day33 贪心(4)

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

先根据气球左边界从小到大排序,然后从左往右遍历,需要维护当前区间最小右边界

写法一:用while循环,不过边界判断和i更新的位置容易出错。当气球的左边界不大于区间右边界,更新右边界end,i增加1;否则,箭的数量增加1。

class Solution:
    def findMinArrowShots(self, points) -> int:
        points.sort(key = lambda x: x[0])
        i = 0
        cnt = 0
        while i < len(points):
            end = points[i][1]
            i += 1
            while i < len(points) and points[i][0] <= end:
                end = min(end, points[i][1])
                i += 1
            cnt += 1
        return cnt

写法二:for循环遍历points,将当前元素的右边界改为区间右边界,每次判断元素左边界与上一个元素的有边界即可。

class Solution:
    def findMinArrowShots(self, points) -> int:
        points.sort(key = lambda x: x[0])
        cnt = 1
        for i in range(1, len(points)):
            if points[i][0] > points[i-1][1]:
                cnt += 1
            else:
                points[i][1] = min(points[i][1], points[i-1][1])
        return cnt

 

435. 无重叠区间 - 力扣(LeetCode)

首先按左边界从小到大将区间排序,接着遍历一次数组,若上一个区间与当前区间不重合,不需要处理;若重合,删掉右边界更靠右的区间(cnt增1),修改当前区间的右边界为更靠左的右边界(因为更靠右的已经删掉了)。

class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals.sort(key = lambda x: x[0])
        cnt = 0

        for i in range(1, len(intervals)):
            if intervals[i-1][1] > intervals[i][0]:
                intervals[i][1] = min(intervals[i][1], intervals[i-1][1])
                cnt += 1
        return cnt

763. 划分字母区间 - 力扣(LeetCode)

解法一:与上面两题思路类似,首先耗费O(1)的空间统计字符串中各字母所在区间:[首次出现位置,最后出现位置],接着按左边界从小到大排序,用left和right维护当前区间的左右边界,若当前字母区间在上一个区间之外,即right<该字母开始位置,就将上一个区间长度推入res,更新left和right为当前字母的左右边界;若当前字母与上一区间重合,需要合并两区间:将right更新为上一区间右界和当前字母右界的较大值。循环结束还有最后一个区间未入res,加入。

易错1:统计时,当第一次遇到一个字母,应该将其右边界也初始化为左边界的值,因为它可能只出现一次。

易错2:通过上一区间右界right判断是否重叠,right更新时也是取自身和当前右界的最大值,而不是考虑上个字母的右界values[i-1][1]。

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        interval = dict()
        for i in range(len(s)):
            c = s[i]
            try:
                interval[c][1] = i
            except KeyError:
                interval[c] = [i, i]

        values = list(interval.values())
        values.sort(key = lambda x: x[0])
        res = []
        left = 0
        right = values[0][1]
        for i in range(1, len(values)):
            if right < values[i][0]:
                res.append(right-left+1)
                left = values[i][0]
                right = values[i][1]
            else:
                right = max(values[i][1], right)

        res.append(right-left+1)

        return res

解法二:用字典保存字母最后出现位置,遍历s,用当前字母最后位置更新区间右界right,若当前下标等于区间右界,说明得到了一个区间,将长度推入res。

class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        interval = dict()
        for i, c in enumerate(s):
            interval[c] = i

        left = 0
        right = interval[s[0]]
        res = []
        for i, c in enumerate(s):
            right = max(right, interval[c])
            if right == i:
                res.append(right-left+1)
                left = i + 1
        return res

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值