思路:
题目的主要信息:
- 对一个数组,每次选1个元素进行操作,两次操作后使数组和最小
- 操作为:任选一个元素x,将数组中所有大于等于x的数减去x
方法一:暴力法
具体做法:
首先对数组进行排序,使之成为递增顺序。求一个数组的和sum,然后就是找到sum要减去的最大值。这个最大值就是进行两次操作的时候要减去的数的总和。
因为数组是递增次数,因此我们如果要减去的元素是,那么从下标
到
全部都可以减去,减去的部分就是
,因此我们可以遍历每个元素,减去1个之后,再对其排序再遍历减去第二个元素,找到能够减去的最大值。
最后sum减去最大值就是所求结果。
class Solution {
public:
long long minimumValueAfterDispel(vector<int>& nums) {
long long sum = 0;
int n = nums.size();
for(int i = 0; i < n; i++)
sum += 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 j = 0; j < n; j++){
int delete2 = temp[j] * (n - j); //减去第二个数
max = max > delete1 + delete2 ? max : delete1 + delete2; //维护最大值
}
temp = nums; //辅助数组回归原来的样子
}
return sum - max;
}
};复杂度分析:
- 时间复杂度:
,第一个排序为
,与后面的比较起来可忽略;第一层遍历是
,循环里面有三个
(分别是减去第一个数、找到减去第二个数的最大值、回归辅助数组),循环里面还有一个sort排序
,故最终的结果是
- 空间复杂度:
,辅助数组temp
方法二:数学分段法
具体做法:
首先将数组排成增序。
遍历的数组中的任意两个数与
,我们可以假设两次减去的数分别为
与
,那么可以分为三种情况:
与之对应的定义域函数分段:
对于情况1:中的数只能减
,
中的数只能减
,
中的数可以减去
,即
对于情况2:中的数只能减
,
之间的数只能减
,
中的数可以才减
,即
对于情况3:中的数只能减
,
中的数只能减
,
中的数才可以减
,即
因此我们遍历两层数组,找到三个边界值index1 index2 index3,然后用区间长度乘上减去的数即可,寻炸这三种情况的最大值,用总和减去最大值即可得到结果。
(以下代码因为遍历顺序问题,i与j与上述相反)
class Solution {
public:
long long minimumValueAfterDispel(vector<int>& nums) {
long long sum = 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++){
sum += 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 sum - max;
}
};复杂度分析:
- 时间复杂度:
,两层循环加一个在外的可忽略的快排
和一个遍历赋值
- 空间复杂度:
,用long long表示的数组numl

京公网安备 11010502036488号