题目名称: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] 。
提示:
-100 <= nums[i] <= 100
思路分析
看见这道题说可以对一个值一直取反,是一个关键, 先把k次机会用在把数组中所有的负数取反, 如果k次机会没有用完,就判断k是否是二的倍数 如果是偶数 让一直对最小的数一直取反,会是正数 如果不是 最小的正数就会变成负数
因为题目要求是求最大和,所以每次变化相反数,只要选择数组中最小的元素即可~
明白这个原理后,最容易想到的就是利用最小堆,每次变换后要求重新计算最小值,这时候优先队列刚号能够满足需求
每次取出最小数字取负,取K此既可。 k次数可以优化,k和数组中负数数量对比,小于等于的时候k次全部使用,当所有数组不存在负数时候,剩余的次数若是偶数则全都对一个数使用则不变,若是奇数只反转最小数既可。
Code实现
public int largestSumAfterKNegations(int[] nums, int k) {
PriorityQueue < Integer > pq = new PriorityQueue < > ();
int ans = 0;
int minusNum = 0;
for (int num: nums) {
if (num < 0) {
minusNum++;
}
pq.offer(num);
ans += num;
}
if (k > minusNum) {
k = ((k - minusNum) & 1) == 1 ? 1 + minusNum : minusNum;
}
while (k > 0) {
int temp = pq.poll();
ans -= temp;
temp = -temp;
pq.offer(temp);
ans += temp;
k--;
}
return ans;
}
结果
算法复杂度分析
- 时间复杂度:
- 空间复杂度: