贪心 1005. K 次取反后最大化的数组和

文章介绍了如何通过贪心策略解决一个数组优化问题。首先提出使用优先级队列每次修改最小元素来最大化和,然后阐述了另一种方法,即先对数组排序,优先转换负数,再根据剩余的修改次数决定是否修改最小值以求得最大和。两种方法都确保了在有限次修改下数组和的最大化。
摘要由CSDN通过智能技术生成

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] <= 100
  • 1 <= k <= 104

思路一

这个是自己想出来的,不愧是自己做出来的根本不知道自己用的是贪心.

我们先来理解一下题意:

他说给你一个数组,你可以修改任意下标的元素,并且可以多次修改,修改k次(nums[i] = -nums[i]),让你返回最大和.

我第一个想法就是,每次修改最小的,然后更新一下,在修改最小的在更新一下.......直到修改k次为止,然后将其数组累加和返回.

那么肯定不能一直更新数组,那我就想到了优先级队列这种数据结构,默认是小根堆,每次弹出的就是最小的元素,然后自动帮我们调整堆.

思路总结

  • 将数组中的所有元素全部放到堆中,他会自动帮你调整堆
  • 然后每次弹出最小的元素,将其修改(nums[i]=-nums[i])
  • 最后将堆中所有元素的累加和返回,就是修改k次的最大累加和
class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for(int i =0;i<nums.length;++i) {
            queue.offer(nums[i]);//将数组元素加入到优先级队列中
        }
        for(int i =0;i<k;++i) {//每次将修改数组中元素最小的那个
            int val = queue.poll();
            queue.offer(-val);
        }
        //修改完之后,将优先级队列中的元素弹出累加之和返回
        int sum = 0;
        while(!queue.isEmpty()) {
            sum += queue.poll();
        }
        return sum;
    }
}

思路二

这个是参考网上大佬写的(英文力扣题解访问次数最高的那个人).

它的思路是这样的,先将数组进行排序(升序排序sort就行).元素大小肯定是从小到大,如果是负的就修改为正的,这样确保负的全变为正的使得整个数组和最大.

然后如果还剩下剩余的修改次数k,那么修改最小的那个元素才会使得整个数组之和最大,如果剩余修改次数是偶数,就不会改变数组和(因为修改两次最小的那个元素不会改变). 如果剩余修改次数是奇数,也是只有修改最小的那个元素才能使得整个数组之和最大,所以需要减去两次最小值min

为什么要减去两次最小值??

比如数组总和为8,数组最小值为2,而这时修改次数为奇数,证明我当是加的应该是-2(6-2)而不是2(6+2).

所以还要将2减去2次(可以理解为减去多加的2,再加上应该加的-2).

根据以上思路,我们肯定要记录最小值

核心思想就是保证数组之和最大,然后修改数组中的最小值,保证最终数组之和最大

也是贪心思想:

保证每次都修改负数为正 达到局部最优

整个数组之和最大,最后如果还剩余修改次数,就修改数组中最小的元素达到全局最优.

思路总结

  • 先将数组进行排序->从小到大.升序
  • 遍历数组元素,进行k次修改,如果元素为负数,将其修改,保证数组之和最大.利用sum累加数组元素
  • 同时记录数组中最小值(全变为正的最小值),以便后续剩余修改次数,方便对其最小值再次进行修改使其数组之和最大达到全局最优.
  • 最后如果没有剩余次数直接返回sum,如果剩余次数为偶数,无论怎么修改最小值都不变,也是直接返回sum,如果是奇数,返回sum-2*min 修改最小值使其数组总和最大
class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        Arrays.sort(nums);//升序排序
        int min = Integer.MAX_VALUE;//记录最小值
        int sum = 0;//路累加和
        for(int i =0;i<nums.length;++i) {
            if(nums[i]<0&&k>0) {//如果是负的就进行修改,同时修改次数--,保证数组之和最大
                nums[i] = -nums[i];
                k--;
            }
            sum += nums[i];//累加数组元素
            min = Math.min(nums[i],min);//记录最小值
        }
        //return k<=0 ? sum : sum - (k%2)*2*min;
        return k<=0 ? sum : (k%2==0) ? sum : sum - 2*min;//这样更容易理解
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值