题目描述
给定一个数组 nums,其中有 n 个非负整数。你的目的是进行两次操作,使得数组的元素之和最小。
每次操作形如:任选一个整数 x ,将数组中所有大于等于 x 的数减去 x 。
方法一:暴力方法
求解思路
对于题目给出的操作规则,我们首先对数组进行排序,使其按照递增的顺序排列。题目要求的数组和,即是原数组进行两次操作以后,减去数的总和。因此我们可以遍历每个元素,进行第一步操作以后再对其进行排序和第二部操作,最终找到能够减去的最大值,即是题目所要求的结果。
解题代码
class Solution {
public:
long long minimumValueAfterDispel(vector<int>& nums) {
long long hysum = 0;
int n = nums.size();
for(int i = 0; i < n; i++)
hysum += nums[i];
vector<int> temp = nums; // 辅助数组
sort(nums.begin(), nums.end()); // 快排
int max = 0;
for(int i = 0; i < n; i++)
{ //减去第一个数
int delete1 = nums[i] * (n - i);
for(int j = i; j < n; j++)
temp[j] -= nums[i];
sort(temp.begin(), temp.end()); // 再次排序
for(int k = 0; k < n; k++)
{ //减去第二个数
int delete2 = temp[k] * (n - k);
max = max > delete1 + delete2 ? max : delete1 + delete2; // 维护最大值
}
temp = nums; // 辅助数组回归原来的样子
}
return hysum - max; // 返回结果
}
};复杂度分析
时间复杂度:外层循环加上内层快排,因此时间复杂度为(
)
空间复杂度:使用辅助数组,引入额外的内存地址空间,因此空间复杂度为
方法二:优化方法
求解思路
(参考复旦大学云影孤帆尽的思路)对于本题目我们可以用数学分段的优化方法来进行解题,首先我们将数组按递增顺序排列,然后任取数组中的两个数nums[i]与nums[j],假设两次减去的数分别为a与b,那么可分为以下三种情况:
1、a=nums[j]-nums[i] b=nums[i]
2、a=nums[i] b=nums[j]-nums[i]
3、a=nums[i] b=nums[j]
然后我们可以想出分段的情况:
1、index1<i<j<n
2、i<index2<j<n
3、i<j<index3<n
然后我们对三种情况分别讨论,当[index1,i]中的数只能减nums[j]-nums[i],[i,j]中的数只能减nums[i],[j,n-1]中的数可以减去nums[j].对于其他两种情况同上述讨论。最后根据上面所述,找到三个边界值,然后用区间长度乘上减去的数即可,最后用总和减去最大值,得到结果。
解题代码
class Solution {
public:
long long minimumValueAfterDispel(vector<int>& nums) {
long long hysum = 0; // 定义变量
long long max = 0;
int n = nums.size();
sort(nums.begin(), nums.end()); // 排序
vector<long long> numl; // 将int转换成long long
for(int i = 0; i < n; i++)
numl.push_back((long long)nums[i]);
for(int i = 0; i < n; i++)
{ //求和
hysum += numl[i];
int index1 = i, index2 = i, index3 = i;
for(int j = 0; j <= i; j++)
{ //找区间边界
while(index1 > 0 && numl[index1 - 1] >= numl[i] - numl[j])
index1--;
while(index2 > i && numl[index2 - 1] >= numl[j] - numl[i])
index2--;
while(index3 < n && numl[index3] < numl[j] + numl[i])
index3++;
//三种情况减去的总和
long long temp1 = (j - index1) * (numl[i] - numl[j]) + (i - j) * numl[j] + (n - i) * numl[i];
long long temp2 = (index2 - j) * numl[j] + (i - index2) * (numl[i] - numl[j]) + (n - i) * numl[i];
long long temp3 = (i - j) * numl[j] + (index3 - i) * numl[i] + (n - index3) * (numl[j] + numl[i]);
max = max > temp1 ? max : temp1; // 维护最大值
max = max > temp2 ? max : temp2;
max = max > temp3 ? max : temp3;
}
}
return hysum - max; // 返回结果
}
};复杂度分析
时间复杂度:两层循环,因此时间复杂度为(
)
空间复杂度:引入数组numl,因此空间复杂度为

京公网安备 11010502036488号