题目
简单
相关标签
给你一个整数数组 nums
和一个整数 k
,按以下方法修改该数组:
- 选择某个下标
i
并将nums[i]
替换为-nums[i]
。
重复这个过程恰好 k
次。可以多次选择同一个下标 i
。
以这种方式修改数组后,返回数组 可能的最大和 。
示例 1:
输入:nums = [4,2,3], k = 1
输出:5
解释:选择下标 1 ,nums 变为 [4,-2,3] 。
示例 2:
输入:nums = [3,-1,0,2], k = 3
输出:6
解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。
示例 3:
输入:nums = [2,-3,-1,5,-4], k = 2
输出:13
解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。
提示:
1 <= nums.length <= 104
-100 <= nums[i] <= 100
1 <= k <= 104
思路和解题方法
- 首先,我们需要对数组进行排序。由于是要使数组中的数尽可能地都为正数,因此我们应该把绝对值小的负数变为正数。
- 这样一来,负数的数量就会减少,而整数和零的数量就会增加,这有利于最终结果更接近最优解。
- 排序后,我们可以从小到大遍历数组,每当遇到一个负数,就将其取反,同时减少可取反的次数 k。
- 这里有个问题,如果我们仅仅只考虑绝对值最小的那个负数,需要取反多少次呢?显然,如果可取反的次数 k 为奇数,那么最终结果就是把绝对值最小的那个负数取反,而如果可取反的次数 k 为偶数,则不需要取反它。
- 另一方面,如果可取反的次数 k 为偶数,那么显然数组中所有的数都会保持不变。最后,我们只需简单地处理一下数组的和即可。
复杂度
时间复杂度:
O(n * logn)
时间复杂度:排序的时间复杂度为 O(nlogn),for 循环的时间复杂度为 O(n),因此总的时间复杂度为 O(nlogn + nlogn + n) = O(nlogn)。
空间复杂度
O(1)
空间复杂度:除了输入的数组外,算法只涉及到常量级别的额外空间。因此空间复杂度为 O(1)。
c++ 代码一
cpp
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end()); // 对数组进行排序,使得负数排在前面
int min1 = 1000; // 初始化绝对值最小的元素为一个较大的数
int min2 = 0; // 记录绝对值最小的元素的索引
for (int i=0; i<nums.size(); i++) {
if(abs(nums[i]) <= min1) { // 如果当前元素的绝对值小于等于min1
min1 = abs(nums[i]); // 更新min1为当前元素的绝对值
min2 = i; // 记录绝对值最小的元素的索引
}
if(nums[i] < 0 && k > 0) { // 如果当前元素是负数且还有剩余的翻转次数
nums[i] *= -1; // 将当前元素取反
k--; // 翻转次数k减一
}
}
if(k%2 == 1) // 如果剩余的翻转次数是奇数
nums[min2] *= -1; // 将绝对值最小的元素取反
int ans = 0;
for(int n : nums)
ans += n; // 计算数组中所有元素的和
return ans; // 返回最终的数组和作为结果
}
};
思路和解题方法二
对数组进行排序
排序函数中采用自定义比较器的方式,把按照绝对值从大到小进行排序。这样排序后,数组中绝对值最大的元素会排在数组的最末尾,而绝对值最小的元素则会排在数组的最前面。
取反负数
遍历数组,如果当前的元素是负数,那么就把它取反(变为正数),同时将剩余可取反次数减一。注意我们要在剩余可取反次数大于 0 且当前元素是负数的情况下才能取反。
处理无法取反的情况
如果我们完成了步骤 2 后,还有剩余可取反的次数,但已经不存在可以被取反的元素了,那么我们需要对数组进行调整,使得我们所取反的元素的绝对值最小。具体地说,我们需要在数组的最末尾找到一个元素,并将它取反。因为这个元素绝对值最大,所以取反后对原来的和的影响最小。由于我们对数组进行了排序,因此直接访问最末尾的元素即可。
计算数组的和
遍历整个数组,计算所有元素之和即可。最终的和就是我们的答案。
复杂度
时间复杂度:
O(n * logn)
时间复杂度:排序的时间复杂度为 O(nlogn),for 循环的时间复杂度为 O(n),因此总的时间复杂度为 O(nlogn + nlogn + n) = O(nlogn)。
空间复杂度
O(1)
空间复杂度:除了输入的数组外,算法只涉及到常量级别的额外空间。因此空间复杂度为 O(1)。
c++ 代码二
cpp
class Solution {
// 定义排序比较器,按照绝对值从大到小排序
static bool cmp(int a, int b) {
return abs(a) > abs(b);
}
public:
int largestSumAfterKNegations(vector<int>& A, int K) {
sort(A.begin(), A.end(), cmp); // 第一步:对数组进行排序
for (int i = 0; i < A.size(); i++) { // 第二步:取反负数
if (A[i] < 0 && K > 0) {
A[i] *= -1;
K--;
}
}
if (K % 2 == 1) A[A.size() - 1] *= -1; // 第三步:处理无法取反的情况
int result = 0;
for (int a : A) result += a; // 第四步:计算数组和
return result;
}
}
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。