[leetcode][1005]K 次取反后最大化的数组和

1.题目描述

//给你一个整数数组 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 
// 
// Related Topics 贪心 数组 排序 
// 👍 211 👎 0

 

2.我的解体思路

  翻译下题目的意思就是,k次对某一个数组元素取反,使得数组所有元素的和最大。

    首先容易想到的就是,我把所有的负数都翻成正数,就能使得数组的和最大了,于是就可以从最小的负数开始,依次翻成正数。

    但是会出现所有的负数都翻完了,但是还没达到k次的要求。这时就只能忍痛割爱,把最小的正数翻成负数。

  经过上面一顿分析,发现有个关键词,最小。就是每次都是需要取反转最小的那个数,一提到最小,脑中就出现一种数据结构,最小堆。

  好了,再翻译下题目的意思就就变成了:对给定数组中最小的数取反,执行k次。当最小的数是0的时候,直接结束取反操作。

  最后再sum下所有的元素就大功告成了。

 

3.代码实现

class Solution {
    int[] smallHeap;
    int heapSize = 0;

    public int largestSumAfterKNegations(int[] nums, int k) {
        smallHeap = new int[nums.length + 5];
        for (int num : nums) {
            addElm(num);
        }
        int smallValue;
        while (k > 0) {
            if (top() == 0) {
                break;
            } else {
                smallValue = -1 * pop();
                addElm(smallValue);
                k--;
            }
        }
        int sum = 0;
        for (int i = 0; i < heapSize; i++) {
            sum += smallHeap[i];
        }
        return sum;
    }

    private void addElm(int newValue) {
        smallHeap[heapSize++] = newValue;
        if (heapSize == 1) {
            return;
        }
        int idx = heapSize - 1;
        int fIdx = (idx - 1) / 2;
        int tmp;
        while (idx > 0) {
            if (smallHeap[idx] < smallHeap[fIdx]) {
                tmp = smallHeap[fIdx];
                smallHeap[fIdx] = smallHeap[idx];
                smallHeap[idx] = tmp;

                idx = fIdx;
                fIdx = (idx - 1) / 2;
            } else {
                break;
            }
        }
    }

    private int top() {
        return smallHeap[0];
    }

    private int pop() {
        int topValue = smallHeap[0];
        smallHeap[0] = smallHeap[--heapSize];
        int idx = 0;
        int lIdx = idx * 2 + 1;
        int rIdx = (idx + 1) * 2;
        while (idx < heapSize) {
            // 有两个子节点
            if (lIdx < heapSize && rIdx < heapSize) {
                // 两个子节点都比当前节点小
                if (smallHeap[lIdx] < smallHeap[idx] && smallHeap[rIdx] < smallHeap[idx]) {
                    if (smallHeap[lIdx] < smallHeap[rIdx]) {
                        idx = changePos(idx, lIdx);
                    } else {
                        idx = changePos(idx, rIdx);
                    }
                } else {
                    if (smallHeap[lIdx] < smallHeap[idx]) {
                        idx = changePos(idx, lIdx);
                    } else if (smallHeap[rIdx] < smallHeap[idx]) {
                        idx = changePos(idx, rIdx);
                    } else {
                        break;
                    }
                }
            } else if (lIdx < heapSize && rIdx >= heapSize) {
                if (smallHeap[lIdx] < smallHeap[idx]) {
                    idx = changePos(idx, lIdx);
                } else {
                    break;
                }
            } else {
                break;
            }
            lIdx = idx * 2 + 1;
            rIdx = (idx + 1) * 2;
        }
        return topValue;
    }

    private int changePos(int idx1, int idx2) {
        int tmp = smallHeap[idx1];
        smallHeap[idx1] = smallHeap[idx2];
        smallHeap[idx2] = tmp;
        return idx2;
    }
}

 

posted on 2022-03-16 15:30  码头整点薯条  阅读(62)  评论(0编辑  收藏  举报

导航