说实话,该题我在做的时候耗费了大量的时间,我的思路改了又改,调试调了又调,可算是调了出来,下面是我写的代码(不过是把所有可能的情况列了出来),代码很冗长
由于我们希望数组的和尽可能大,因此除非万不得已,我们应当总是修改负数,并且优先修改值最小的负数。因为将负数 -x修改成 x 会使得数组的和增加 2x,所以这样的贪心操作是最优的。
- 当给定的 K 小于等于数组中负数的个数时,我们按照上述方法从小到大依次修改每一个负数即可。但如果 K 的值较大,那么我们不得不去修改非负数(即正数或者 0)了。由于修改 0 对数组的和不会有影响,而修改正数会使得数组的和减小,因此:
- 如果数组中存在 0,那么我们可以对它进行多次修改,直到把剩余的修改次数用完;
- 如果数组中不存在 0 并且剩余的修改次数是偶数,由于对同一个数修改两次等价于不进行修改,因此我们也可以在不减小数组的和的前提下,把修改次数用完;
- 如果数组中不存在 0 并且剩余的修改次数是奇数,那么我们必然需要使用单独的一次修改将一个正数变为负数(剩余的修改次数为偶数,就不会减小数组的和)。为了使得数组的和尽可能大,我们就选择那个最小的正数。
需要注意的是,在之前将负数修改为正数的过程中,可能出现了(相较于原始数组中最小的正数)更小的正数,这一点不能忽略。
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());//先排序
int cn_fu=0,sign_0=0;
for(int i=0;i<nums.size();i++)
{
if(nums[i]==0)
{
sign_0=1;//判断有没有0
}
if(nums[i]<0)//计算负数的个数
{
cn_fu++;
}
}
int check=k-cn_fu;//将负数都变成正的之后还有多少次反转操作
int minnum=1000;
if(k<=cn_fu)//如果操作次数k小于等于负数个数,直接全部变成正的即可
{
for (int i = 0; i <cn_fu; i++)
{
nums[i] = -nums[i];
k--;
if(k==0)
{
break;
}
}
}
else
{
if(sign_0)//如果有0,就先将负数变正之后k清0(因为全部用在0上)
{
for (int i = 0; i <cn_fu; i++)
{
nums[i] = -nums[i];
k--;
}
k=0;
}
else//没有0
{
if(check%2==0)//剩余操作数是偶数,负数变正之后,k清0
{
for (int i = 0; i <cn_fu; i++)
{
nums[i] = -nums[i];
k--;
if(k==check)
{
break;
}
}
k=0;
}
else//剩余操作数是奇数
{
for(int i=0;i<cn_fu;i++)
{
nums[i]=-nums[i];
k--;
for(int i=0;i<nums.size();i++)//每次更新数组之后找最小正数
{
if(nums[i]>0)
{
minnum=min(minnum,nums[i]);
}
}
if(k==check)
{
break;
}
}
for (int i = 0; i < nums.size(); i++)
{
if (nums[i] > 0)
{
minnum = min(minnum, nums[i]);
}
}
for(int i=0;i<nums.size();i++)
{
if(nums[i]==minnum)//找到最小正数将其取反
{
nums[i]=-nums[i];
break;
}
}
}
}
}
int sum = 0;
for (int i = 0; i < nums.size(); i++)
{
sum += nums[i];
}
return sum;
}
};
实际上,上面冗长的if分类操作我们只需要再用一个sort就能解决(LeetCode上的题解,感慨自己思维不够敏捷^~^)
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());//先排序
int sum=0;
for(int i=0;i<nums.size();i++)
{
if(nums[i]<0&&k>0)//一边取反一边求和
{
nums[i]=-nums[i];
k--;
}
sum+=nums[i];
}
sort(nums.begin(),nums.end());//全部取反之后直接找到最小正数
if(k%2==0)
{
return sum;
}
else
{
return sum-2*nums[0];//补上减去那个最小正数(本来没减反而加上,所以现在减2倍)
}
}
};