题目链接
image.png

  1. /**
  2. * @param {number[]} nums
  3. * @param {number} k
  4. * @return {number}
  5. */
  6. const numsToNumber = (nums) => {
  7. if (nums.length === 0) {
  8. return 0;
  9. }
  10. return nums.reduce((prev, next) => {
  11. return prev + next;
  12. });
  13. };
  14. var largestSumAfterKNegations = function (nums, k) {
  15. if (nums.length === 0) {
  16. return 0;
  17. }
  18. nums.sort((prev, next) => {
  19. return prev - next;
  20. });
  21. const l1 = nums.filter((num) => { return num < 0 }).sort((prev, next) => {
  22. return prev - next;
  23. });
  24. const t = k % 2 === 0;
  25. // 考虑无复数的情况
  26. if (l1.length === 0 && t) {
  27. return numsToNumber(nums);
  28. } else if (l1.length === 0 && !t) {
  29. return numsToNumber(nums) - 2 * nums[0];
  30. }
  31. // 到这里开始考虑数组内有负数的情况
  32. const t2 = (k - l1.length) <= 0; //考虑k与负数个数的关系
  33. if (t2) {
  34. return numsToNumber(nums.filter((num) => { return num >= 0 })) - numsToNumber(l1.slice(0, k)) + numsToNumber(l1.slice(k, l1.length));
  35. }
  36. const t3 = (k - l1.length) % 2 === 0; //k > l1.length
  37. // t3
  38. if (t3) {
  39. return numsToNumber(nums.map((num) => { return Math.abs(num) }));
  40. }
  41. const l2 = nums.map((num) => { return Math.abs(num) }).sort((prev, next) => {
  42. return prev - next;
  43. });
  44. return numsToNumber(l2) - 2 * l2[0];
  45. };

思路:贪心算法

  1. 首先判断nums内有无负数(利用 l1 的长度来计算)以及k的奇偶性code01.png
  2. l1.length===0的情况下,如果k为偶数则自我抵消,对原数组无任何影响;若k为奇数则需要令nums的和减去两倍的nums中的最小值:code03.png
  3. 当l1.length>0时,我们首先考虑l1.length与k的差值大于等于0的特殊情况

1005. K 次取反后最大化的数组和 - 图4
code02.png

  1. 接下来讨论l1.length < k的情况,此时如果(l1.length-k)%2===0,则k可以将l1中的负数全部取反,由于还会剩下偶数次取反的机会可以自我抵消(负负得正),因此我们只需要将nums全部取绝对值相加即可

code04.png

  1. 若l1.length < k且(l1.length-k)%2!==0,则首先: code05.png

由上可知l2是nums经过取绝对值并排序过后的数组,在这种情况下由于我们必须做出“牺牲”,令l2之中最小的值消耗完取反次数,则此时这个最小值会为负数,我们需要的结果就是l2的总和减去2倍的该最小值:
code06.png

ps.本人水平有限,欢迎批评指正