Medium
题目描述
有 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 <= 10^5
- 1 <= milestones[i] <= 10^9
解题思路
这是一道贪心算法问题。核心思想是分析在不能连续工作同一项目的约束下,最多能工作多少周。
分析思路:
首先考虑理想情况:如果没有连续工作限制,我们可以工作的总周数就是所有里程碑的总和。但由于不能连续工作同一项目,我们需要分析什么情况下会受到限制。
关键观察:限制我们工作周数的主要因素是最大里程碑数的项目。如果某个项目的里程碑数过多,我们可能无法在其他项目之间穿插完成所有工作。
贪心策略:
设最大里程碑数为 maxMilestones,其余所有项目里程碑总和为 otherSum。
如果
maxMilestones <= otherSum + 1,说明我们可以通过在最大项目和其他项目之间交替工作,完成所有里程碑。此时答案是所有里程碑的总和。如果
maxMilestones > otherSum + 1,说明最大项目的里程碑过多,我们最多只能工作2 * otherSum + 1周(在其他项目之间穿插最大项目的工作)。
推荐解法: 贪心算法,时间复杂度O(n),空间复杂度O(1),是最优解法。
代码实现
class Solution {
public:
long long numberOfWeeks(vector<int>& milestones) {
long long total = 0;
long long maxMilestones = 0;
for (int milestone : milestones) {
total += milestone;
maxMilestones = max(maxMilestones, (long long)milestone);
}
long long otherSum = total - maxMilestones;
if (maxMilestones <= otherSum + 1) {
return total;
} else {
return 2 * otherSum + 1;
}
}
};
class Solution:
def numberOfWeeks(self, milestones: List[int]) -> int:
total = sum(milestones)
max_milestones = max(milestones)
other_sum = total - max_milestones
if max_milestones <= other_sum + 1:
return total
else:
return 2 * other_sum + 1
public class Solution {
public long NumberOfWeeks(int[] milestones) {
long total = 0;
long maxMilestones = 0;
foreach (int milestone in milestones) {
total += milestone;
maxMilestones = Math.Max(maxMilestones, milestone);
}
long otherSum = total - maxMilestones;
if (maxMilestones <= otherSum + 1) {
return total;
} else {
return 2 * otherSum + 1;
}
}
}
/**
* @param {number[]} milestones
* @return {number}
*/
var numberOfWeeks = function(milestones) {
let total = 0;
let maxMilestones = 0;
for (let milestone of milestones) {
total += milestone;
maxMilestones = Math.max(maxMilestones, milestone);
}
let otherSum = total - maxMilestones;
if (maxMilestones <= otherSum + 1) {
return total;
} else {
return 2 * otherSum + 1;
}
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历一次数组计算总和和最大值 |
| 空间复杂度 | O(1) | 只使用常数额外空间 |
相关题目
- . Task Scheduler (Medium)