1953. 你可以工作的最大周数

【算法题】最多能工作多少周?—《按规则完成项目阶段任务》题解

题目描述

给你 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
第8周不能执行,因为连续两周会做项目0任务,违反规则。

解题分析

这道题的核心是 如何在「不能连续两周完成同一个项目任务」的规则限制下,最大化完成任务的周数

直觉

  • 如果所有项目的任务数比较均衡,比如 [1, 2, 3],你可以交替完成不同项目的任务,直到完成所有任务,最大周数就是任务总数之和。
  • 但如果某一个项目任务数远远多于其他项目,比如 [10, 2],就会出现「任务太集中导致无法连续交替完成」的问题。

关键点

我们关注两个指标:

  • max_m = 最大任务数(任务最多的项目)
  • rest = 其余项目任务数的总和

总任务数为 total = sum(milestones)


规则推导

  • 如果最大任务数 max_m 小于或等于其他项目任务数之和加 1,即
max_m <= rest + 1

则说明任务比较均衡,可以保证交替完成任务,不会因为同一项目任务太多而被卡住。

此时,可以完成所有任务,总周数为:

total
  • 如果最大任务数远大于其他项目任务总和,则受限于不能连续两周完成同一项目任务的规则,完成的最大周数为:
2 * rest + 1

这是因为最多你可以将其他项目的任务穿插在最大任务项目之间,每个其他项目任务都允许插入一个最大任务项目任务形成交替。这样形成的最长序列长度是 2 * rest + 1


解题方法

根据以上分析,算法很简单:

  1. 计算总任务数 total 和最大任务数 max_m
  2. 计算剩余任务数 rest = total - max_m
  3. 如果 max_m <= rest + 1,返回 total
  4. 否则返回 2 * rest + 1

代码实现(Python)

from typing import List

class Solution:
    def numberOfWeeks(self, milestones: List[int]) -> int:
        total = sum(milestones)
        max_m = max(milestones)
        rest = total - max_m

        if max_m <= rest + 1:
            return total
        else:
            return 2 * rest + 1

复杂度分析

  • 时间复杂度:O(n),遍历一次数组计算总和和最大值。
  • 空间复杂度:O(1),使用常数额外空间。

示例说明

以示例 [5, 2, 1] 为例:

  • 总任务数 total = 8
  • 最大任务数 max_m = 5(项目0)
  • 其余任务数 rest = 3

判断:

  • max_m <= rest + 15 <= 3 + 15 <= 4不成立

所以最大周数为:

2 * rest + 1 = 2 * 3 + 1 = 7

这和示例输出相符。


总结

这道题通过简单的数学推导和贪心思路,巧妙地解决了「不能连续两周做同一个项目」的限制。它归结为判断最大任务项目与其他任务项目的任务数量关系,从而推断最大可工作的周数。

掌握这类问题的思路,可以帮助你应对更多涉及任务调度和交替执行的限制类题目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值