思路:
题目的主要信息:
- 对一个数组,每次选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