贪心2:K 次取反后最大化的数组和
Posted 纵横千里,捭阖四方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪心2:K 次取反后最大化的数组和相关的知识,希望对你有一定的参考价值。
我们说贪心算法很多解题思路是我们先 看出来了,然后只是用代码实现而已,这个题就很典型:
LeetCode1005,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] 。
首先看一下这个题目是什么意思。意思就是我们要将某个数取反,可以只针对一个数,也可以针对多个数,但是一定要执行K次不断的取反。例如第一个例子是4,2,3,我们只反转一次,很显然反转2为-2,则结果为4+3-2=5最大,如果反转4或者3都会比5小,所以输出5。
而对于第二个3,-1,0,2,反转3次,很显然我们可以看到将-1转成正的,剩下的就是来回取反0,最大为6。当然也可以将-1取反3次得到1。
最后一个2,-3,-1,5,-4,有三个负数,而K=2只能取反两次,所以我们自然要选择最小的两个负数-3和-4,这样序列就变成了2,3,-1,5,4结果为13,最大。
很显然上面这个过程就是小学生也知道的方法。如果告诉你是个贪心问题,反而会吓跑一大波人,我们这里只是用贪心来包装了一下而已。
贪心的思路是局部最优:让绝对值大的负数变为正数,当前数值达到最大。整体最优:整个数组和达到最大。局部最优可以推出全局最优。
那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让数组和达到最大。此时只找数值最小的正整数进行反转(局部最优),当前数值可以达到最大(全局最优)。
如果要变成能用代码解决的问题,大致有这么几个步骤:
- 1带着正负号,将数组小到大排序
- 2从前向后遍历,遇到负数将其变为正数,同时K--
- 3如果负数没有了,K还大于0,那么反复反转绝对值最小的元素,将K用完
- 4求和
但是这么做的话,当负数都转完了,K还不是0,接下来的处理有点麻烦,我们可以按照绝对值进行排序,然后,再从后往前遍历,遇到负数反转,再到正数跳过,当然,这里我们可以边遍历边累加,最后,如果 k 还有剩余且为奇数,只要减去第一个数的绝对值的两倍即可。
class Solution
public int largestSumAfterKNegations(int[] nums, int k)
List<Integer> list = new ArrayList<>();
for (int num : nums)
list.add(num);
list.sort((a, b) -> Math.abs(a) - Math.abs(b));
int ans = 0;
for (int i = list.size() - 1; i >= 0; i--)
if (k > 0 && list.get(i) < 0)
ans += -list.get(i);
k--;
else
ans += list.get(i);
if (k % 2 != 0)
ans -= 2 * Math.abs(list.get(0));
return ans;
这个题从不同的角度考虑至少有七八种方法能解决 ,感兴趣的小伙伴可以研究一下。
以上是关于贪心2:K 次取反后最大化的数组和的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode1005 K次取反后最大化的数组和(贪心+Java简单排序)