翻转增益的最大子数组和 Java题解| 豆包MarsCode AI刷题

178 阅读3分钟

翻转增益的最大子数组和

问题描述

给定整数数组,我们称其中连续的 0 个或多个整数为一个子数组,求翻转任一子数组后,新数组中子数组的和的最大值

输入格式

第一行输入为 N,代表数组长度

第二行输入为 N 个整数,依次为数组的每个元素

输出格式

一个整数 K,代表所有可能新数组中子数组的和的最大值

输入样例

5

1 2 3 -1 4

输出样例

10

说明

选择翻转子数组 [-1, 4] 或 [1, 2, 3, -1],新数组分别是 [1, 2, 3, 4, -1] 和 [-1, 3, 2, 1, 4],二者的子数组最大和都是 10

数据范围

50% case:1 <= N <= 100-100<= arr[i] <= 100

100% case:1 <= N <= 1e6-100<= arr[i] <= 100

问题理解

我们需要找到一个整数数组中,通过翻转任意一个子数组后,新数组中子数组的和的最大值。

关键点

  1. 子数组:连续的0个或多个整数。
  2. 翻转:将子数组中的元素顺序颠倒。
  3. 最大和:翻转后的新数组中,所有可能的子数组的和的最大值。

解题思路

  1. 计算原始数组的最大子数组和

    • 使用Kadane算法可以在O(N)时间内计算出原始数组的最大子数组和。
  2. 计算翻转子数组的影响

    • 翻转一个子数组会影响该子数组及其周围的元素。
    • 翻转子数组后,新的子数组和可能会发生变化。
  3. 考虑翻转的子数组

    • 翻转的子数组可以是任意长度的,从1到N。
    • 需要考虑翻转后对整个数组的影响,特别是翻转后子数组的和的变化。
  4. 计算翻转后的最大子数组和

    • 需要遍历所有可能的翻转子数组,计算翻转后的新数组的最大子数组和。
    • 可以通过预处理数组,计算出每个位置翻转后的影响,从而优化计算。

解题代码

public class Main {
    public static int solution(int N, int[] data_array) {
        //将主数组中的数字求和,判断初始数组和
        int originalMaxSum = kadane(data_array);
        int maxSumAfterFlip = originalMaxSum;
        //遍历数组,找出所有子数组
        for (int i = 0; i < N; i++) {
            for (int j = i; j < N; j++) {
                //翻转当前子数组
                int[] flippedArray = flipSubarray(data_array, i, j);
                //求出最大子数组和
                int flippedMaxSum = kadane(flippedArray);
                maxSumAfterFlip = Math.max(maxSumAfterFlip, flippedMaxSum);
            }
        }

        return maxSumAfterFlip;
    }

    private static int kadane(int[] array) {
        int maxSum = array[0];//最大字数组和,初始为a[0]
        int curSum = array[0];//当前字数组和
        for(int i = 1;i < array.length;i++){
            //判断字数组是否为负
            if(curSum < 0){
                curSum = array[i];//初始化子数组和
            }else{
                curSum += array[i];
            }
            if (curSum > maxSum) {
                maxSum = curSum;//找出数组最大子数组和
            }
        }
        return maxSum;
    }

    private static int[] flipSubarray(int[] array, int start, int end) {
        int[] flippedArray = array.clone();//复制数组
        //判断是否遍历完成,从头到尾交换数字
        while (start < end) {
            int temp = flippedArray[start];
            flippedArray[start] = flippedArray[end];
            flippedArray[end] = temp;
            start++;
            end--;
        }
        return flippedArray;
    }

    public static void main(String[] args) {
        System.out.println(solution(5, new int[] { 1, 2, 3, -1, 4 }) == 10);
        int[] array1 = { -85, -11, 92, 6, 49, -76, 28, -16, 3, -29, 26, 37, 86, 3, 25, -43, -36, -27, 45, 87, 91, 58,
                -15, 91, 5, 99, 40, 68, 54, -95, 66, 49, 74, 9, 24, -84, 12, -23, -92, -47, 5, 91, -79, 94, 61, -54,
                -71, -36, 31, 97, 64, -14, -16, 48, -79, -70, 54, -94, 48, 37, 47, -58, 6, 62, 19, 8, 32, 65, -81, -27,
                14, -18, -34, -64, -97, -21, -76, 51, 0, -79, -22, -78, -95, -90, 4, 82, -79, -85, -64, -79, 63, 49, 21,
                97, 47, 16, 61, -46, 54, 44 };
        System.out.println(solution(100, array1) == 1348);
    }
}

AI搜题给了我解题思路,并且教会了我kadane函数(求数组最大子数组和)。 收获匪浅。