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

154 阅读5分钟

今天带来的是豆包MarsCode AI刷题的一道题:翻转增益的最大子数组和。

1、首先我们还是老样子,先来看一下题目,看看题目要我们干什么:

image.png

题目给的几个条件:
  1. 给你一个数组data_array的长度
  2. 再给你一个data_array数组
  3. 只允许你进行一次数组的翻转
  4. 你需要用1次或者0次翻转找到data_array数组的哪一个子数组的和最大
  5. 输出这个最大和

好了,题目条件提取出来了,现在脑子嗡嗡的,啥。这是人提出来的要求?要我自己选择要不要翻转,我怎么知道。。。我不会!

看一下样例:

{BDA1CB3A-FDEF-4DA5-9920-FD00D02C6D3C}.png

其实我们读完题目,把条件提取出来后,就会有一点点的小思路。比如,我哪知道要选择翻转哪一部分才能使得子数组的和尽量大,我们用一句话秒了:小孩子才做选择,我都翻一遍。

好的,这样你就等到了一个初步的思路,我每一种翻转情况都试一遍,看看哪一次翻转后其子数组的和最大

等等!那我要怎么找到这一次翻转后的子数组的最大和???没思路。。。对了,我能不能直接来两个for循环来计算!

打住打住!你这里两个for循环,你这两个for循环外面还再次套两个for循环。。。你这哪门子算法,不会写别写了,换一道题吧!

不行我要优化一下这个查找最大和的子数组!!!

2、优化查找过程。
经过我的仔细思考,我发现了:这个过程好像又是一个选择题:
  1. 对于每一个元素它有三种状态
  2. 第一种状态是他被我选择了
  3. 第二种状态是他被我选择当作子数组的头元素
  4. 第三种状态是他没有被我选到

那我就用动态规划把他秒了!(定义一个check函数来检查每一次翻转后数组a的子数组的最大和) 这里补充补充一下:子数组是连续的一段区间

  1. 我们选择用一个变量来记录当前翻转后的数组其子数组的最大和mx
  2. 再来用一个变量cur来记录我们在遍历这个数组的时候,当前我们在计算的子数组的和,因为我们计算的不可能只是一个子数组,有很多个~
  3. 重点来了:for(int i=0;i<N;++i)遍历这个数组的时候,我们到底要不要继续拓展我们当前正在计算的子数组的和(cur) 还是 重新起一个头?这就取决于cur+a[i]与a[i]哪个大了,因为a[i]有可能是一个负数
  4. 如果cur+a[i]>=a[i],那么我们就选择继续扩展当前子数组
  5. 如果cur+a[i]<a[i],那么我们选择重新起一个头,因为选择了这个a[i]还给我负贡献,我怎么可能愿意!!!
  6. 上面的操作用代码表示即:cur=max(a[i],cur+a[i])
  7. 每一次比完,我们都会跟mx进行比较,即mx=max(mx,cur)

因此我们得到check函数的代码:注意mx,cur初始化的时候是数组的第一个元素:

public static int check(int a[]){
        int mx=a[0];
        int cur=a[0];
        for(int i=1;i<a.length;++i){
            cur=Math.max(a[i],cur+a[i]);
            mx=Math.max(mx,cur);
        }
        return mx;
    }

对了,还需要一个翻转数组的函数,相信你们都会,就不解释了~:

public static int[] rev(int[] a,int start,int end){
        int []t=Arrays.copyOf(a, a.length);
        while(start<end){
            int tt=t[start];
            t[start]=t[end];
            t[end]=tt;
            end--;
            start++;
        }
        return t;
    }

最后在solution函数的代码就不用多说了吧,两个for循环,直接上完整代码!!!!

import java.util.Arrays;

public class Main {
    public static int solution(int N, int[] data_array) {
       int ans=check(data_array);
        for(int i=0;i<N;++i){
        for(int j=i+1;j<N;++j){
            ans=Math.max(ans,check(rev(data_array,i,j)));
        }
       }
       return ans;
    }
    public static int[] rev(int[] a,int start,int end){
        int []t=Arrays.copyOf(a, a.length);
        while(start<end){
            int tt=t[start];
            t[start]=t[end];
            t[end]=tt;
            end--;
            start++;
        }
        return t;
    }
    public static int check(int a[]){
        int mx=a[0];
        int cur=a[0];
        for(int i=1;i<a.length;++i){
            cur=Math.max(a[i],cur+a[i]);
            mx=Math.max(mx,cur);
        }
        return mx;
    }

    public static void main(String[] args) {
        // You can add more test cases here
        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(5, new int[] { 1, 2, 3, -1, 4 }) == 10);
        System.out.println(solution(100, array1) == 1348);
    }
}

最后总结一下:你这两个for循环还得练!因为还可以优化这两个for循环!!!