Day22: 贪心算法 | 区间问题,左/右端点排序

1.452用最少数量的箭引爆气球

只按右端点排序(左端点大小无所谓),射在右端点,尽可能多射到气球

python 复制代码
class Solution:
    def findMinArrowShots(self, points: List[List[int]]) -> int:
        points.sort(key = lambda x :x[1])
        arrows = 1
        position = points[0][1]

        for point in points[1:]:
            if point[0] > position:
                arrows += 1
                position = point[1]
        return arrows 

2.435. 无重叠区间

和上一题一样,这俩题本质是一道题,也是只按右端点排序,重叠则删除右端点大的区间,这样可以尽可能避免重叠。

python 复制代码
class Solution:
    def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        intervals.sort(key = lambda x :x[1])
        n = len(intervals)
        remove = 0
        curr_end = intervals[0][1]
        for i in range(1,n):
            if intervals[i][0] < curr_end:
                remove += 1
            else:
                curr_end = intervals[i][1]
        return remove

3.763. 划分字母区间

缝缝补补才写出来,我的方法太过于复杂

构建字典 → 提取区间 → 排序 → 合并区间

python 复制代码
class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        res = []
        
        char_intervals = defaultdict(list)
        for i,ch in enumerate(s):
            if ch not in char_intervals:
                char_intervals[ch] = [i,i]
            char_intervals[ch][1] = i
        
        intervals = list(char_intervals.values())
        intervals.sort(key = lambda x: x[0])
        start = 0
        curr_end = intervals[0][1]
        for interval in intervals:
            if interval[0] > curr_end:
                res.append(curr_end-start+1 )
                curr_end = interval[1]
                start = interval[0]     
            else:
                curr_end = max(curr_end, interval[1])       

        res.append(curr_end-start+1) 
        
        return res

优化:

只记录字符最后一次出现的位置,遍历字符,扩展end边界。

python 复制代码
class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        last_index = {ch: i for i, ch in enumerate(s)}
        
        res = []
        start = end = 0
        
        for i, ch in enumerate(s):
            end = max(end, last_index[ch])
            
            if i == end:
                res.append(end - start + 1)
                start = i + 1
        
        return res

4.56. 合并区间

python 复制代码
class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        intervals.sort(key = lambda x:x[0])
        res = [intervals[0]]
        for interval in intervals[1:]:
            if interval[0] > res[-1][1]:
                res.append(interval)
            else:
                start,end = res.pop()
                res.append([start, max(interval[1],end)])
            
        return res

优化:else部分,可以直接修改,不用pop

python 复制代码
res[-1][1] = max(res[-1][1],interval[1])

6.738. 单调递增的数字

我想的是从左往右扫描,需要回溯去找mark的位置,逻辑比较复杂

  1. str不能直接修改,转换为list修改
  2. 字符比较大小时通过ASCII码比较,这里是单个字符,可以直接比较大小 ('1'与'5')
  3. 处理重复数字用while,这里回头往前探测
  4. 找到mark,将数字减一,注意字符与数字的转换
  5. 后面的字符全改为'9'
  6. 字符拼接并转为int
    1. int可以直接处理0开头的字符串,'019'-->19
python 复制代码
class Solution:
    def monotoneIncreasingDigits(self, n: int) -> int:
        #找到第一个下降的数字
        #找到它前面的数字(可能有重复)-1,后面全为9
        #字符与数字的转换
        digits = list(str(n)) #['1','5','0']
        n = len(digits)
        mark = None
        for i in range(n):
            if i > 0 and digits[i] < digits[i-1]:
                mark = i-1
                while mark > 0 and digits[mark-1] == digits[mark]:
                    mark -= 1
                break
        if mark is not None:
            digits[mark] = str(int(digits[mark]) - 1)
            for i in range(mark+1, n):
                digits[i] = '9'
        
        return int(''.join(digits))
        

优化:从右往左扫描,不用回溯逻辑清晰多了。老是忘记初始化mark。。

python 复制代码
class Solution:
    def monotoneIncreasingDigits(self, n: int) -> int:
        digits = list(str(n))
        n = len(digits)
        mark = n #随便一个不存在的位置
        for i in range(n-1, 0,-1):#[n-1,1]
            if digits[i-1] > digits[i]:
                digits[i-1] = str(int(digits[i-1]) -1)
                mark = i-1
        for i in range(mark+1, n):
            digits[i] = '9'
        
        return int(''.join(digits))
相关推荐
三毛的二哥2 小时前
BEV:典型BEV算法总结
人工智能·算法·计算机视觉·3d
南宫萧幕2 小时前
自控PID+MATLAB仿真+混动P0/P1/P2/P3/P4构型
算法·机器学习·matlab·simulink·控制·pid
故事和你914 小时前
洛谷-数据结构1-4-图的基本应用1
开发语言·数据结构·算法·深度优先·动态规划·图论
我叫黑大帅4 小时前
为什么map查找时间复杂度是O(1)?
后端·算法·面试
炽烈小老头4 小时前
【每天学习一点算法 2026/04/20】除自身以外数组的乘积
学习·算法
skilllite作者5 小时前
AI agent 的 Assistant Auto LLM Routing 规划的思考
网络·人工智能·算法·rust·openclaw·agentskills
py有趣6 小时前
力扣热门100题之不同路径
算法·leetcode
_日拱一卒7 小时前
LeetCode:25K个一组翻转链表
算法·leetcode·链表
啊哦呃咦唔鱼7 小时前
LeetCodehot100-394 字符串解码
算法
小欣加油7 小时前
leetcode2078 两栋颜色不同且距离最远的房子
数据结构·c++·算法·leetcode·职场和发展