作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级
活动选择问题是算法研究中的一个经典问题,广泛应用于资源分配领域,如会议室预订、课程安排等场景。问题的核心是在给定一组活动,每个活动都有一个开始时间和一个结束时间,要求选择最大数量的互不重叠的活动。
问题定义
给定( n )个活动,每个活动( i )都有一个开始时间 ( s_i )和结束时间 ( e_i )。选择一组最大的互不相交的活动集合,即在任意选定的两个活动( i )和( j ),满足( i =!j ),则( e_i <= s_j )或( e_j <= s_i )。
贪心选择策略
活动选择问题的贪心策略是基于活动的结束时间进行选择,即总是选择结束时间最早的活动。按照这种策略进行选择的理由如下:
- 选择结束最早的活动将留给剩余活动最大的时间空间,从而增加后续选择活动的可能性。
- 这种策略确保了每次选择都是局部最优的,即在当前剩余的活动集合中,选择一个与已选择的活动都不重叠且结束最早的活动。
算法步骤
- 输入:活动时间对列表 ((s_1, e_1), (s_2, e_2), …, (s_n, e_n))。
- 排序:按照活动的结束时间( e_i )进行升序排序。
- 初始化:选择排序后的第一个活动,因为它的结束时间最早。
- 迭代选择:
- 从剩余的活动中选择一个与已选择集合中所有活动都不重叠的活动,具体为选择结束时间最早且开始时间不早于最后一个已选择活动的结束时间的活动。
- 输出:返回选择的活动集合。
示例代码
以下是用 Python 实现的活动选择问题的贪心算法:
def activity_selection(activities): """ 贪心算法选择最大的互不相交活动集 :param activities: 列表,每个元素是元组(start_time, end_time) :return: 最大互不相交活动集 """ # 按活动的结束时间进行升序排序 sorted_activities = sorted(activities, key=lambda x: x[1]) # 选择的活动集 selected_activities = [] # 最后一个选择活动的结束时间 last_end_time = 0 # 遍历排序后的活动列表 for start, end in sorted_activities: if start >= last_end_time: selected_activities.append((start, end)) last_end_time = end return selected_activities # 给定的活动列表 activities = [(1, 4), (3, 5), (0, 6), (5, 7), (8, 9), (5, 9)] # 获取最大互不相交的活动集 max_activities = activity_selection(activities) # 打印结果 print("Selected activities (Start, End):") for activity in max_activities: print(activity)
算法分析
- 时间复杂度:排序活动的时间复杂度为 ( O(n log n) ),选择活动的时间复杂度为 ( O(n) ),因此总时间复杂度为 ( O(n log n) )。
- 空间复杂度:算法的空间复杂度为 ( O(1) ),如果不考虑输入数据的存储,只需常数空间用于索引和临时变量。
为了更清晰地理解活动选择问题及其贪心算法实现,我们可以通过图解的方式来逐步展示算法的工作原理。图解将帮助我们可视化贪心选择策略是如何在实践中被应用以解决问题的。
活动选择问题的图解
以下一组活动,每个活动都有一个开始时间和结束时间:
步骤 1: 活动按结束时间排序
活动编号 | 开始时间 | 结束时间 |
1 | 1 | 4 |
2 | 3 | 5 |
3 | 0 | 6 |
4 | 5 | 7 |
5 | 8 | 9 |
6 | 5 | 9 |
步骤 2: 选择活动
接下来,我们选择结束时间最早的活动,并排除所有与其重叠的活动:
- 选择活动 1 (结束时间 4) - 选择这个活动因为它是第一个结束的。
- 排除活动 2 (因为它在活动 1 还未结束时开始了,即与活动 1 重叠)。
- 排除活动 3 (同样重叠于活动 1)。
- 选择活动 4 (下一个未重叠活动,开始时间 5,结束时间 7)。
- 排除活动 6 (与活动 4 重叠)。
- 选择活动 5 (下一个未重叠活动,开始时间 8,结束时间 9)。
图解表示
以下是活动时间线的图示,显示了如何选择活动:
时间线: 0---------1---------2---------3---------4---------5---------6---------7---------8---------9 活动 1: [-----------------------------] 活动 2: [--------------------] 活动 3: [-----------------------------------------------------------] 活动 4: [-------------------] 活动 5: [----------] 活动 6: [----------------------------------------]
选择的活动: 1, 4, 5
步骤 3: 最终结果
我们最终选择的活动集合为活动 1, 4, 5,这是根据贪心算法从排序后的活动列表中选择的最大互不相交集。
结论
活动选择问题的贪心算法非常高效且易于实现。通过基于结束时间的排序和选择,它可以找到最大的互不相交的活动集合,适用于许多实际的调度和资源分配问题。此外,该问题的解法也深刻地体现了贪心算法设计的美妙和实用性,即通过每步的局部最优选择达到全局最优解
欢迎关注微信公众号 数据分析螺丝钉