There are n
projects numbered from 0
to n - 1
. You are given an integer array milestones
where each milestones[i]
denotes the number of milestones the ith
project has.
You can work on the projects following these two rules:
Once all the milestones of all the projects are finished, or if the only milestones that you can work on will cause you to violate the above rules, you will stop working. Note that you may not be able to finish every project's milestones due to these constraints.
Return the maximum number of weeks you would be able to work on the projects without violating the rules mentioned above.
Example 1:
Input: milestones = [1,2,3] Output: 6 Explanation: One possible scenario is: - During the 1st week, you will work on a milestone of project 0. - During the 2nd week, you will work on a milestone of project 2. - During the 3rd week, you will work on a milestone of project 1. - During the 4th week, you will work on a milestone of project 2. - During the 5th week, you will work on a milestone of project 1. - During the 6th week, you will work on a milestone of project 2. The total number of weeks is 6.
Example 2:
Input: milestones = [5,2,1] Output: 7 Explanation: One possible scenario is: - During the 1st week, you will work on a milestone of project 0. - During the 2nd week, you will work on a milestone of project 1. - During the 3rd week, you will work on a milestone of project 0. - During the 4th week, you will work on a milestone of project 1. - During the 5th week, you will work on a milestone of project 0. - During the 6th week, you will work on a milestone of project 2. - During the 7th week, you will work on a milestone of project 0. The total number of weeks is 7. Note that you cannot work on the last milestone of project 0 on 8th week because it would violate the rules. Thus, one milestone in project 0 will remain unfinished.
Constraints:
n == milestones.length
1 <= n <= 105
1 <= milestones[i] <= 109
This problem asks for the maximum number of weeks you can work on projects given constraints on working on milestones. The key insight is to use a greedy approach. We don't need to simulate the process of working week by week; instead, we can determine the maximum number of weeks directly based on the distribution of milestones.
Core Idea:
The maximum number of weeks is limited by two factors:
Algorithm:
s
): Sum up all the milestones in the milestones
array.mx
): Find the largest number of milestones in a single project.rest
): Subtract the maximum milestones from the total milestones (s - mx
). This represents the total milestones in all other projects.mx
(milestones in the largest project) is greater than rest + 1
, then the largest project's milestones will be limiting factor. In this case, we can complete all milestones in other projects and then almost all milestones in the largest project (all except one). The maximum weeks in this scenario is rest * 2 + 1
.mx <= rest + 1
, then we can complete all milestones, and the maximum number of weeks is simply the total number of milestones (s
).Time and Space Complexity:
Python3:
class Solution:
def numberOfWeeks(self, milestones: List[int]) -> int:
mx, s = max(milestones), sum(milestones)
rest = s - mx
return rest * 2 + 1 if mx > rest + 1 else s
Java:
class Solution {
public long numberOfWeeks(int[] milestones) {
int mx = 0;
long s = 0;
for (int e : milestones) {
s += e;
mx = Math.max(mx, e);
}
long rest = s - mx;
return mx > rest + 1 ? rest * 2 + 1 : s;
}
}
C++:
class Solution {
public:
long long numberOfWeeks(vector<int>& milestones) {
int mx = *max_element(milestones.begin(), milestones.end());
long long s = accumulate(milestones.begin(), milestones.end(), 0LL);
long long rest = s - mx;
return mx > rest + 1 ? rest * 2 + 1 : s;
}
};
Go:
func numberOfWeeks(milestones []int) int64 {
mx := slices.Max(milestones)
s := 0
for _, x := range milestones {
s += x
}
rest := s - mx
if mx > rest+1 {
return int64(rest*2 + 1)
}
return int64(s)
}
TypeScript:
function numberOfWeeks(milestones: number[]): number {
const mx = Math.max(...milestones);
const s = milestones.reduce((a, b) => a + b, 0);
const rest = s - mx;
return mx > rest + 1 ? rest * 2 + 1 : s;
}
All these code snippets implement the same greedy algorithm, differing only in syntax and standard library functions used for finding the maximum and sum of elements. They all achieve the optimal time and space complexity.