题目:
给你 n
个项目,编号从 0
到 n - 1
。同时给你一个整数数组 milestones
,其中每个 milestones[i]
表示第 i
个项目中的阶段任务数量。
你可以按下面两个规则参与项目中的工作:
- 每周,你将会完成 某一个 项目中的 恰好一个 阶段任务。你每周都 必须 工作。
- 在 连续的 两周中,你 不能 参与并完成同一个项目中的两个阶段任务。
一旦所有项目中的全部阶段任务都完成,或者仅剩余一个阶段任务都会导致你违反上面的规则,那么你将 停止工作 。注意,由于这些条件的限制,你可能无法完成所有阶段任务。
返回在不违反上面规则的情况下你 最多 能工作多少周。
示例 1:
输入:milestones = [1,2,3] 输出:6 解释:一种可能的情形是: - 第 1 周,你参与并完成项目 0 中的一个阶段任务。 - 第 2 周,你参与并完成项目 2 中的一个阶段任务。 - 第 3 周,你参与并完成项目 1 中的一个阶段任务。 - 第 4 周,你参与并完成项目 2 中的一个阶段任务。 - 第 5 周,你参与并完成项目 1 中的一个阶段任务。 - 第 6 周,你参与并完成项目 2 中的一个阶段任务。 总周数是 6 。
示例 2:
输入:milestones = [5,2,1] 输出:7 解释:一种可能的情形是: - 第 1 周,你参与并完成项目 0 中的一个阶段任务。 - 第 2 周,你参与并完成项目 1 中的一个阶段任务。 - 第 3 周,你参与并完成项目 0 中的一个阶段任务。 - 第 4 周,你参与并完成项目 1 中的一个阶段任务。 - 第 5 周,你参与并完成项目 0 中的一个阶段任务。 - 第 6 周,你参与并完成项目 2 中的一个阶段任务。 - 第 7 周,你参与并完成项目 0 中的一个阶段任务。 总周数是 7 。 注意,你不能在第 8 周参与完成项目 0 中的最后一个阶段任务,因为这会违反规则。 因此,项目 0 中会有一个阶段任务维持未完成状态。
提示:
n == milestones.length
1 <= n <= 105
1 <= milestones[i] <= 109
解题:
在这个问题中,我们面对的是一种调度问题,我们的目标是最大化在给定规则下可以工作的周数。基于这个问题的特性,我们可以分析出关键的思路:我们不能连续两周工作在同一个项目上,这意味着当一个项目的任务多于其他所有项目的总和时,这个项目就会变成瓶颈。
因此,我们的核心策略是,尽可能平均地在所有项目中分配任务。如果一个项目的任务过多,超过了其他所有项目任务数的总和,那么多出来的部分就无法完成,因为我们没有足够的"间隙"去安排它们。考虑到这一点,我们可以通过找出任务最多的项目,然后判断它的任务数是否超过其他所有项目任务数的总和来解决这个问题。
代码:
public long numberOfWeeks(int[] milestones) {
long max = 0; // 用于记录任务最多的项目的任务数
long sum = 0; // 用于记录所有项目任务数的总和
for (int milestone : milestones) {
max = Math.max(max, milestone);
sum += milestone;
}
long rest = sum - max; // 计算除了任务最多的项目外,其他所有项目任务数的总和
if (max > rest) {
// 如果任务最多的项目的任务数超过了其他所有项目的总和,
// 那么最多能工作的周数就是2倍的其他所有项目的总和加上1,
// 因为每周可以在两个不同的项目之间交替,最后加上最开始工作的那周。
return 2 * rest + 1;
} else {
// 如果没有一个项目的任务数超过了其他所有项目的总和,
// 那么可以完成所有的任务,总周数就是所有任务的总和。
return sum;
}
}
知识点讲解:
-
基本数据类型与运算:
- 使用了
long
类型来定义变量,这是因为milestones[i]
的取值范围可能导致其总和超出int
类型的最大值。 - 使用了
for
循环来遍历数组,这是处理数组中每个元素的常用方法。 - 使用了
Math.max()
方法来找到数组中的最大值,这是Java标准库提供的一个非常方便的方法,用于比较两个数值并返回较大值。
- 使用了
-
条件语句:
- 使用了
if-else
条件判断结构,根据一个项目的任务数和其他所有项目任务数的总和的比较结果,来选择不同的计算路径。
- 使用了
-
算法思维:
- 利用算法思想分析问题,通过计算和比较得到结果。核心是理解问题的本质,将它转化为数学或逻辑问题,然后使用编程技巧解决。
-
累加和问题:
- 在遍历时对数组元素进行累加,常用于求解数组中元素的和。本例中,通过累加来计算所有项目的总任务数。
-
数组处理:
- 整个解决方案中使用数组来表示每个项目的阶段任务数,对数组的处理是实现算法的基础。
-
复杂度理解:
- 理解代码执行的时间复杂度,本代码具有O(n)的时间复杂度,这是因为它通过一次遍历完成了所有需要的计算。
下表总结了上述提到的一些关键点及其在代码中的应用:
知识点 | 描述 | 应用 |
---|---|---|
基本数据类型与运算 | 使用基本数据类型定义变量,使用算术运算符进行计算。 | 使用long 定义变量,Math.max() 进行最大值比较 |
条件语句 | 根据条件执行不同的代码路径。 | 使用if-else 结构根据条件进行不同的周数计算 |
算法思维 | 分析问题的本质,并设计有效的程序解决方案。 | 分析任务分配策略,采用适合的算法计算最大工作周数 |
累加和问题 | 对数组或数列中的元素进行累加以求和。 | 遍历数组进行累加以求得总任务数 |
数组处理 | 使用数组存储和处理数据集合。 | 使用数组milestones 保存每个项目的阶段任务数 |
复杂度理解 | 理解代码执行所需的时间与资源,以优化性能。 | 本解决方案通过一次数组遍历(O(n))来计算结果, |