题目
1005. K 次取反后最大化的数组和
简单
相关标签
贪心 数组 排序
给你一个整数数组 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] <= 1001 <= 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++ 代码一
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++ 代码二
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;
    }
}
 
 
觉得有用的话可以点点赞,支持一下。
如果愿意的话关注一下。会对你有更多的帮助。
每天都会不定时更新哦 >人< 。




















