今天带来的是豆包MarsCode AI刷题的一道题:翻转增益的最大子数组和。
1、首先我们还是老样子,先来看一下题目,看看题目要我们干什么:
题目给的几个条件:
- 给你一个数组data_array的长度
- 再给你一个data_array数组
- 只允许你进行一次数组的翻转
- 你需要用1次或者0次翻转找到data_array数组的哪一个子数组的和最大
- 输出这个最大和
好了,题目条件提取出来了,现在脑子嗡嗡的,啥。这是人提出来的要求?要我自己选择要不要翻转,我怎么知道。。。我不会!
看一下样例:
其实我们读完题目,把条件提取出来后,就会有一点点的小思路。比如,我哪知道要选择翻转哪一部分才能使得子数组的和尽量大,我们用一句话秒了:小孩子才做选择,我都翻一遍。
好的,这样你就等到了一个初步的思路,我每一种翻转情况都试一遍,看看哪一次翻转后其子数组的和最大
等等!那我要怎么找到这一次翻转后的子数组的最大和???没思路。。。对了,我能不能直接来两个for循环来计算!
打住打住!你这里两个for循环,你这两个for循环外面还再次套两个for循环。。。你这哪门子算法,不会写别写了,换一道题吧!
不行我要优化一下这个查找最大和的子数组!!!
2、优化查找过程。
经过我的仔细思考,我发现了:这个过程好像又是一个选择题:
- 对于每一个元素它有三种状态
- 第一种状态是他被我选择了
- 第二种状态是他被我选择当作子数组的头元素
- 第三种状态是他没有被我选到
那我就用动态规划把他秒了!(定义一个check函数来检查每一次翻转后数组a的子数组的最大和) 这里补充补充一下:子数组是连续的一段区间
- 我们选择用一个变量来记录当前翻转后的数组其子数组的最大和
mx - 再来用一个变量
cur来记录我们在遍历这个数组的时候,当前我们在计算的子数组的和,因为我们计算的不可能只是一个子数组,有很多个~ - 重点来了:
for(int i=0;i<N;++i)遍历这个数组的时候,我们到底要不要继续拓展我们当前正在计算的子数组的和(cur) 还是 重新起一个头?这就取决于cur+a[i]与a[i]哪个大了,因为a[i]有可能是一个负数 - 如果
cur+a[i]>=a[i],那么我们就选择继续扩展当前子数组 - 如果
cur+a[i]<a[i],那么我们选择重新起一个头,因为选择了这个a[i]还给我负贡献,我怎么可能愿意!!! - 上面的操作用代码表示即:
cur=max(a[i],cur+a[i]) - 每一次比完,我们都会跟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循环!!!