题目描述:
给你一个整数数组 nums
和一个整数 k
,按以下方法修改该数组:
- 选择某个下标
i
并将nums[i]
替换为-nums[i]
。
重复这个过程恰好 k
次。可以多次选择同一个下标 i
。
以这种方式修改数组后,返回数组 可能的最大和
示例一:
输入:nums = [4,2,3], k = 1
输出:5
解释:选择下标 1 ,nums 变为 [4,-2,3]
示例二:
输入:nums = [3,-1,0,2], k = 3
输出:6
解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。
示例三:
输入:nums = [2,-3,-1,5,-4], k = 2
输出:13
解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。
问题解决:
这道题其实要考虑的是数组中负数的个数和转变次数的大小从而进行分类讨论的问题:
假设数组中负数的个数是m,转变次数是k:
1.当m <= k的时候:
直接将前k小的数组中的负数转化成正数,然后返回数组和。
2.当 m > k的时候:
直接将数组中所有的负数转换成正数,然后再进行判断:
(1)(k - m) % 2 == 0:
直接返回结果,因为剩余的转换次是偶数次,相当于取一个数进行不停的转换偶数次,最终结果还
是这个数本身,所以可以直接返回。
(2)(k - m) % 2 != 0:
对应的转换次数是奇数次,对应必须要有一个数转换成负数,为了是数组和最大,所以需要找到数
组中最小的数将其转换成负数,再将数组的和返回即可。
对应的代码:
准备工作:统计数组中的负数的个数,将数组排序:
sort(nums.begin(),nums.end());
int count = 0;
for(int i = 0;i < nums.size();i++)
{
if(nums[i] < 0)
{
count++;
}
else
{
break;
}
}
1.当m <= k的时候:
if(count >= k)
{
for(int i = 0;i < k;i++)
{
nums[i] = -nums[i];
}
return SumofNums(nums);
}
int SumofNums(vector<int>& nums)
{
int ret = 0;
for(int i = 0;i <nums.size();i++)
{
ret += nums[i];
}
return ret;
}
2.当 m > k的时候:
(1)(k - m) % 2 == 0:
else
{
for(int i = 0;i < count;i++)
{
nums[i] = -nums[i];
}
if((k - count) % 2 == 0)
{
return SumofNums(nums);
}
else
{
nums[FindMin(nums)] = -nums[FindMin(nums)];
return SumofNums(nums);
}
}
(2)(k - m) % 2 != 0:
else
{
nums[FindMin(nums)] = -nums[FindMin(nums)];
return SumofNums(nums);
}
int FindMin(vector<int>& nums)
{
int j = 0;
int min1 = INT_MAX;
for(int i = 0;i <nums.size();i++)
{
if(nums[i] < min1)
{
min1 = nums[i];
j = i;
}
}
return j;
}
对应的完整代码:
class Solution
{
public:
int SumofNums(vector<int>& nums)
{
int ret = 0;
for(int i = 0;i <nums.size();i++)
{
ret += nums[i];
}
return ret;
}
int FindMin(vector<int>& nums)
{
int j = 0;
int min1 = INT_MAX;
for(int i = 0;i <nums.size();i++)
{
if(nums[i] < min1)
{
min1 = nums[i];
j = i;
}
}
return j;
}
int largestSumAfterKNegations(vector<int>& nums, int k)
{
sort(nums.begin(),nums.end());
int count = 0;
for(int i = 0;i < nums.size();i++)
{
if(nums[i] < 0)
{
count++;
}
else
{
break;
}
}
if(count >= k)
{
for(int i = 0;i < k;i++)
{
nums[i] = -nums[i];
}
return SumofNums(nums);
}
else
{
for(int i = 0;i < count;i++)
{
nums[i] = -nums[i];
}
if((k - count) % 2 == 0)
{
return SumofNums(nums);
}
else
{
nums[FindMin(nums)] = -nums[FindMin(nums)];
return SumofNums(nums);
}
}
}
};
这种代码是看着最易懂的,但还可以被优化,优化如下:
class Solution
{
public:
int largestSumAfterKNegations(vector<int>& nums, int k)
{
int m = 0;
int minElem = INT_MAX;
int n = nums.size();
for(auto x:nums)
{
if(x < 0) m++;
minElem = min(minElem,abs(x));
}
//分类讨论:
int ret = 0;
if(m >= k)
{
sort(nums.begin(),nums.end());
for(int i = 0;i < k;i++)
{
ret += -nums[i];
}
for(int i = k;i < n;i++)
{
ret += nums[i];
}
}
else
{
//将所有的负数变成正数
for(auto x : nums)
{
ret += abs(x);
}
if((k - m) % 2)
{
ret -= 2 * minElem;
}
}
return ret;
}
};
这就是这道题的解法。