前缀和+贪心总结,基于每日一题力扣3439、3440

昨天的每日一题又出现前缀和+贪心,分析了半天知道用贪心,但没想到要使用前缀和运算,总结记录下。

力扣题目 3439[重新安排会议得到最多空余时间 I]

eventTime代表活动总时长,startTimeendTime标识活动中有n个会议,第i个会议时间为 startTime[i], endTime[i]
k代表能移动的会议数量。
要求:移动会议,获得最大的连续没有会议的空闲时间

例:将 [1, 2] 的会议安排到 [2, 3] ,得到空余时间 [0, 2] 。输出:2

我的思路

首先想到动态规划,假设dp[i]代表到i能获得到的最长时间,
dp_0为初始0,dp_i=dp_i-1...

发现无法建立状态转移方程,通俗说就是没办法通过之前的最长时间获得下1个会的最长时间。

然后思考贪心 做法,发现最优解一定存在于某个连续的 k 个会议子集中;
问题转化 :计算连续的k个会议的空闲时间合并,然后比较那个子集的休息时间最大就是答案。

k个会议就最多会有 k+1 个休息时间。 假设休息时间开始为left,结束为right。总的休息时间就是 right-left-所有会议时间总和。

所以从i=k-1开始遍历,计算出每个子集最大的空闲时间。

前缀和优化 :复杂度为 On(从k-1遍历到n计算每个子集) * (O1(计算left与right)*On(计算会议总和))

会发现总时间负责度到了On^2。需要优化,这里就需要用前缀和预处理会议时间总和。做到O1查询结果。

python 复制代码
class Solution:
    def maxFreeTime(self, eventTime: int, k: int, startTime: List[int], endTime: List[int]) -> int:
        n = len(startTime)
        # 处理边界情况
        if n == 0 or k == 0:
            return eventTime
        
        # 预处理前缀和数组,pre_sum[i]表示前i个会议的总时长
        pre_sum = [0] * (n + 1)
        for i in range(n):
            pre_sum[i+1] = pre_sum[i] + (endTime[i] - startTime[i])
        
        max_free = 0  # 记录最大空闲时间
        
        # 遍历所有可能的连续k个会议的子集
        for i in range(k-1, n):
            left, right = 0, 0  # 初始化空闲区间的左右边界
            
            # 计算空闲区间的左边界
            if i <= k-1:
                # 前k个会议的左边界是0
                left = 0
            else:
                # 非前k个会议的左边界是第i-k个会议的结束时间
                left = endTime[i-k]
            
            # 计算空闲区间的右边界
            if i < n-1:
                # 当前会议不是最后一个会议时,右边界是下一个会议的开始时间
                right = startTime[i+1]
            else:
                # 当前会议是最后一个会议时,右边界是整个活动的结束时间
                right = eventTime
            
            # 计算当前连续k个会议的总时长
            total_event_time = pre_sum[i+1] - pre_sum[i-k+1]
            
            # 计算当前子集对应的空闲时间
            current_free = right - left - total_event_time
            
            # 更新最大空闲时间
            max_free = max(max_free, current_free)
        
        return max_free
复杂度分析
  • 时间复杂度:O (n),主要来自前缀和数组的预处理和一次遍历。
  • 空间复杂度:O (n),主要用于存储前缀和数组。

力扣题目 3440[重新安排会议得到最多空余时间 II]

eventTime代表活动总时长,startTimeendTime标识活动中有n个会议,第i个会议时间为 startTime[i], endTime[i]

只能移动1个会议;注意:会议顺序可以改变。

要求:移动会议,获得最大的连续没有会议的空闲时间

我的思路

咋一看还以为是昨天的题目固定K=1的情况,洋洋洒洒写完了才发现不对。

会议顺序可以改变 就导致两个情况:

1、如果其他空位能够安排要移动的第i个会议,答案为right-left

2、如果不能安排,答案为 right-left-(endTime[i]-startTime[i])

如何判断其他空位是否能够安排第i个会议

遍历i, 对所有其他空位计算是否能够放下会议。(复杂度为On^2)

需要用1次遍历计算是否有空位放置会议。使用双向遍历预处理i之前的空格最大值,判断是否能放下i。如果做不到1个循环判断i与n-i+1,可以用两个循环实现。

python 复制代码
class Solution:
    def maxFreeTime(self, eventTime: int, startTime: List[int], endTime: List[int]) -> int:
        n = len(startTime)
        if n == 0:  # 处理边界情况:没有会议
            return eventTime
        
        # 预处理数组q:q[i]表示第i个会议是否可以被安排到其他空闲位置
        q = [False] * n
        
        # t1 记录从左到右遍历过程中遇到的最大空闲区间长度
        # t2 记录从右到左遍历过程中遇到的最大空闲区间长度
        t1 = 0
        t2 = 0
        
        # 双向遍历预处理每个会议左右两侧的最大空闲区间
        for i in range(n):
            # 处理第i个会议左侧的空闲区间
            current_gap_left = startTime[i] - (0 if i == 0 else endTime[i-1])
            if endTime[i] - startTime[i] <= t1:
                q[i] = True  # 如果当前会议时长小于等于左侧最大空闲区间,则可以安排
            t1 = max(t1, current_gap_left)  # 更新左侧最大空闲区间
            
            # 处理第n-i-1个会议右侧的空闲区间(从右向左遍历)
            j = n - i - 1
            current_gap_right = (eventTime if i == 0 else startTime[j+1]) - endTime[j]
            if endTime[j] - startTime[j] <= t2:
                q[j] = True  # 如果当前会议时长小于等于右侧最大空闲区间,则可以安排
            t2 = max(t2, current_gap_right)  # 更新右侧最大空闲区间
        
        # 计算最大空闲时间
        res = 0
        for i in range(n):
            # 计算移除第i个会议后的左右边界
            left = 0 if i == 0 else endTime[i-1]
            right = eventTime if i == n-1 else startTime[i+1]
            
            if q[i]:
                # 如果第i个会议可以被安排到其他位置,则其原占用时间完全消除
                res = max(res, right - left)
            else:
                # 否则,需要减去该会议的时长
                res = max(res, right - left - (endTime[i] - startTime[i]))
        
        return res
复杂度分析
  • 时间复杂度:O (n),两次线性遍历和一次结果计算
  • 空间复杂度 :O (n),主要用于存储预处理数组 q
相关推荐
这里有鱼汤28 分钟前
小白必看:QMT里的miniQMT入门教程
后端·python
TF男孩10 小时前
ARQ:一款低成本的消息队列,实现每秒万级吞吐
后端·python·消息队列
该用户已不存在15 小时前
Mojo vs Python vs Rust: 2025年搞AI,该学哪个?
后端·python·rust
NAGNIP17 小时前
大模型框架性能优化策略:延迟、吞吐量与成本权衡
算法
站大爷IP17 小时前
Java调用Python的5种实用方案:从简单到进阶的全场景解析
python
美团技术团队18 小时前
LongCat-Flash:如何使用 SGLang 部署美团 Agentic 模型
人工智能·算法
用户8356290780511 天前
从手动编辑到代码生成:Python 助你高效创建 Word 文档
后端·python
Fanxt_Ja1 天前
【LeetCode】算法详解#15 ---环形链表II
数据结构·算法·leetcode·链表
侃侃_天下1 天前
最终的信号类
开发语言·c++·算法
c8i1 天前
python中类的基本结构、特殊属性于MRO理解
python