3494: Find-the-Minimum-Amount-of-Time-to-Brew-Potions
Medium
table of contents
For this question, I intend to iterate through each potion
inside mana and iterate through each wizard inside
skill to calculate the consequent time each wizard
completes each potion by. Since, to calculate the completion times of
each potion, we only need the completion times of the previous
potion, we can afford to reduce the space complexity by making our
dp matrix have a row size of 2.
int n = skill.size(), m = mana.size();
vector<vector<long long>> dp (2, vector<long long>(skill.size(), 0));Now, the main part that I realised was is that, in the examples
provided, each potion had a column denoting the
start-time that the potion is worked on. If you remove
the start-time from each row, then each row in
dp is just a zero-initialised prefix sum array
that you can easily calculate in one-pass.
For example:
Potion Number Start time Wizard 0 done by Wizard 1 done by Wizard 2 done by Wizard 3 done by
0 0 5 30 40 60
1 52 53 58 60 64After subtracting the start time from each done by time, we have:
Potion Number Start time Wizard 0 done by Wizard 1 done by Wizard 2 done by Wizard 3 done by
0 0 5 30 40 60
1 0 1 6 8 12where, we can see that:
- if
j == 0,dp[i][j]is justmana[i] * skill[j] - if
j > 0,dp[i][j]is justdp[i][j-1] + mana[i] * skill[j]
Therefore, while we iterate through the array skill for
each potion, we need to be able to calculate the potion’s respective
start-time and increase it every time the consequent
wizard is unable to handle the current potion using the recurrence
relationship:
currStartTime += max((long long) 0, (prevStartTime + dp[0][j]) - (currStartTime + dp[1][j-1]));Now, for the code, we first have to initialise the first row of
values in dp:
dp[1][0] = mana[0] * skill[0];
for (int j = 1; j < n; ++j) {
dp[1][j] = dp[1][j-1] + mana[0] * skill[j];
}Then, combining all the previous logic, if we iterate through all the potions and wizards, we get:
long long prevStartTime = 0, currStartTime = 0;
for (int i = 1; i < m; ++i) {
dp[0] = dp[1]; // shift the "current" row into the "previous" row
prevStartTime = currStartTime; // shift the "current" time into the "previous" time
currStartTime += dp[0][0]; // currStartTime will always be delayed by dp[0][0]
dp[1][0] = mana[i] * skill[0]; // initialise the first value in the dp row
for (int j = 1; j < n; ++j) {
currStartTime += max((long long) 0, prevStartTime + dp[0][j] - currStartTime - dp[1][j-1]);
dp[1][j] = dp[1][j-1] + mana[i] * skill[j];
}
}
return currStartTime + dp.back().back();code
class Solution {
public:
long long minTime(vector<int>& skill, vector<int>& mana) {
int n = skill.size(), m = mana.size();
vector<vector<long long>> dp (2, vector<long long>(skill.size(), 0));
dp[1][0] = mana[0] * skill[0];
for (int j = 1; j < n; ++j) {
dp[1][j] = dp[1][j-1] + mana[0] * skill[j];
}
long long prevStartTime = 0, currStartTime = 0;
for (int i = 1; i < m; ++i) {
dp[0] = dp[1];
prevStartTime = currStartTime;
currStartTime += dp[0][0];
dp[1][0] = mana[i] * skill[0];
for (int j = 1; j < n; ++j) {
currStartTime += max((long long) 0, prevStartTime + dp[0][j] - currStartTime - dp[1][j-1]);
dp[1][j] = dp[1][j-1] + mana[i] * skill[j];
}
}
return currStartTime + dp.back().back();
}
};