力扣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] 。

贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让数组和达到最大,那么我们只要将最小的正整数取反即可,这样取到的和最大。

法一:
class Solution {
    
    
    public int largestSumAfterKNegations(int[] nums, int k) {
    
    
        /**
        贪心思想:绝对值排序
        */
        //先将数组根据绝对值从小到大进行排序
        nums = IntStream.of(nums)
		     .boxed()
		     .sorted((o1, o2) -> Math.abs(o1) - Math.abs(o2))
		     .mapToInt(Integer::intValue).toArray();
        //遍历数组 遇到负数且k>0 就将负数取反
        //要从后向前进行取反 先将绝对值大的负数进行取反
        for(int i=nums.length-1;i>=0;i--){
    
    
            if(nums[i] < 0 && k > 0){
    
    
                nums[i] = -nums[i];
                k--;
            }
        }
        //看k是否还剩余,如果是奇数,就将最小的正整数取反即可
        if(k % 2 == 1){
    
    
            nums[0] = -nums[0];
        }
        //数组求和
        return Arrays.stream(nums).sum();
    }
}
法二*(效率稍微高一些 代码复杂一些):
class Solution {
    
    
    public int largestSumAfterKNegations(int[] nums, int k) {
    
    
        Arrays.sort(nums);
        int fuNums = 0;
        int num_0 = -1;
        int res = 0;
        
        for(int i=0;i<nums.length;i++){
    
    
            if(nums[i] < 0){
    
    
                fuNums++;
            }
            if(nums[i] == 0){
    
    
                num_0 = i;  //找到0的下标位置
                break;
            }
        }
        int cnt = k - fuNums; //k与负数的差值
        //System.out.println("fushu"+fuNums);
        //负数大于等于k的情况下
        if(fuNums >= k){
    
    
            res = adds(nums,k);
        }else if(fuNums > 0){
    
    
            //负数小于k
            if(num_0 >= 0 || (cnt%2==0)){
    
    
            //存在0的情况
            //先将所有的负数取反 其余的取反次数全部在零上作用
                res = adds(nums,fuNums);
                //System.out.println("26hang");
            }else{
    
    
                //没有零的情况
                int a = -(nums[fuNums-1]);
                if(fuNums<nums.length){
    
    
                    int b = nums[fuNums];
                    if(a >= b){
    
    
                        nums[fuNums] = -(nums[fuNums]);
                    }else{
    
    
                        nums[fuNums-1] = -(nums[fuNums-1]);
                    }
                }else{
    
    
                    nums[fuNums-1] = -(nums[fuNums-1]);
                }
                
                res = adds(nums,fuNums);
            }
        }else{
    
    
            if(k%2==0){
    
    
                res = adds(nums,0);
            }
            else{
    
    
                res = adds(nums,1);
            }
        }
        return res;
    }
    public int adds(int num[],int fuNum){
    
    
        int ress = 0;
        for(int i=0;i<fuNum;i++){
    
    
            ress += (-num[i]);  //将所有的负数取反
        }
        for(int i=fuNum;i<num.length;i++){
    
    
            ress += num[i];
        }
        return ress;
    }
}

猜你喜欢

转载自blog.csdn.net/xiaoning9299/article/details/126680770