题目描述
有n个水桶,第i个水桶里面水的体积为Ai,你可以用1秒时间向一个桶里添加1体积的水。
有q次询问,每次询问一个整数pi,你需要求出使其中pi个桶中水的体积相同所花费的最少时间。
对于一次询问如果有多种方案,则采用使最终pi个桶中水的体积最小的方案。
方法一:动态规划的思想
求解思路
对于求解本题目,我们可以使用动态规划的思想,我们用dp[i]表示前i个数的和。对于题目所提到的每次询问,我们看成第i次查询的说法。我们要求需要有p[i]个相同水量的水桶,根据前面的叙述,我们可以得到花费的公式为:sum=a[j-1]*p[i]-(dp[j]-dp[j-p[i]]).然后我们遍历后续数组找到花费的最小值,并将水桶之前的水量修改为当前水桶的水量,并以此进行,得到题目的最后结果。
解题代码
class Solution { public: vector<int> solve(int n, int q, vector<int>& a, vector<int>& p) { vector<int> myres(q, 0); // 记录结果 vector<int> dp(n + 1, 0); sort(a.begin(), a.end()); // 快排 for(int i = 0; i < q; i++) { for(int j = 1; j <= n; j++) dp[j] = dp[j - 1] + a[j - 1]; // 计算前缀和 int Min = INT_MAX, sum = 0; int pos = 0; // 记录修改到水一样多时的位置 for(int j = p[i]; j <= n; j++) { //寻找最小花费时间,前面p[i]个已经相等,从后面开始找 sum = a[j - 1] * p[i] - (dp[j] - dp[j - p[i]]); if(sum < Min) { Min = min(sum, Min); pos = j; } } for(int j = pos - 1; j > pos - p[i]; j--) a[j - 1] = a[pos - 1]; myres[i] = Min; } return myres; // 返回结果 } };
复杂度分析
时间复杂度:两层循环,因此时间复杂度为( )
空间复杂度:使用dp数组,引入额外的内存地址空间,因此空间复杂度为
方法二:迭代的思想
求解思路
对于方法一,我们对其进行改进,在每次迭代的过程中,我们用变量记录其前缀和,而不是使用方法一的辅助数组,其余的操作和方法一相同,并得到最终的答案。
解题代码
class Solution { public: vector<int> solve(int n, int q, vector<int>& a, vector<int>& p) { vector<int> myres(q, 0); // 存储结果 sort(a.begin(), a.end()); // 快排 int maxsame = 1, same = 1; for (int i = 1; i < n; i++) { //找出数组中大小相同并且相同个数最多的元素的个数 if (a[i] == a[i - 1]) same++; else { maxsame = max(maxsame, same); same = 1; } } int Min = 0; int pos = 0; for (int i = 0; i < q; i++) { if (p[i] > maxsame) { //先与当前最大相同水桶数比较 int sum = 0; for (int j = 0; j < p[i]; j++) sum += a[j]; Min = a[p[i] - 1] * p[i] - sum; pos = p[i] - 1; for (int j = p[i]; j < n; j++) { //遍历数组,看是否有比上面时间更短的 sum -= a[j - p[i]] - a[j]; if (Min > a[j] * p[i] - sum) { Min = a[j] * p[i] - sum; pos = j; } } myres[i] = Min; for (int j = pos - p[i] + 1; j < pos; j++) // 修改pos之前的 a[j] = a[pos]; maxsame = p[i]; } } return myres; // 返回结果 } };
复杂度分析
时间复杂度:两层循环,因此时间复杂度为( )
空间复杂度:没有引入额外的内存地址空间,因此空间复杂度为