今天我们还是来看之前写的那一道题的题解~
:啥?还讲?不是讲过了吗,我都会了,你还来这道题???骗我流量,再见!
别别别,再拿这一道题来讲是有原因的~
什么原因?难不成你还想再水一篇?
怎么可能水一篇,只是觉得上次讲的这道题的题解那个算法还是太慢了。。。
那道题还慢???都从嵌套四个for循环优化到两个了,你还嫌慢。等你优化完我又写了一道题了,来来来,请开始你的表演:
我还不是觉得嵌套两个for循环太丑了,能不能优雅点,把O的复杂优化成O(n)的复杂度。。。废话不多说,直接上才艺
1、首先我们还是来看题目(上次看完忘记了):
题目给的几个条件:
- 给你一个数组data_array的长度
- 再给你一个data_array数组
- 只允许你进行一次数组的翻转
- 你需要用1次或者0次翻转找到data_array数组的哪一个子数组的和最大
- 输出这个最大和
根据上次的讲解,我们已经对这道题比较了解了,但是上次优化的是查找翻转后的数组的子数组的最大和,把原本要O()的时间复杂度优化成O(n)的复杂度,但是你有没有发现,模拟翻转的过程是不太必要的,为什么?
如果你观察翻转的过程,你会发现每次翻转就是把你选的子数组的后面一半的元素换到前面来。
既然是找一个子数组的后面一半换到前面来,题目要求我们寻找到一个翻转后的数组的其中某个子数组的和尽可能的大,那这个过程是不是就是上一篇讲的,用动态规划来寻找一个子数组的最大和,然后把这个子数组翻转过去。很好,感觉真的可以把这个时间复杂度继续优化下去!!!!
既然已经知道要怎么找翻转过来的元素,那是不是后面的这个最大我们就选他呢?其实不是,因为你还要考虑在翻转的这个数组区间的第一个元素的前面一部分,综合起来考虑,前面和后面两个加起来最大才可以,不能只顾前面或者后面。
好的,那我们再来总结一下思路:
- 我们现在在一个循环
for(int i=N-2;i>=0;--i)里面,为什么是i=N-2?因为我们还要初始化数据,即max_r[N-1]=a[i-1],还有一个cur_r=a[i-1]这个什么作用就不用说了吧,和上一篇作用一样,对于每一个i,进行cur_r=max(cur+a[i],a[i]); - 我们需要从数组的后面往前遍历(因为你从后往前遍历的时候,就确保了每一个以i为起始的子数组往其后的某个连续区间,一定可以确保你把i位置后面的最大和的子数组翻转到前面,这个需要你多思考一下,或者画图去理解一下,比较难想通)
- 对于每一个i位置,再进行一次
max_r[i]=max(max_r[i+1],cur) - 遍历完以后我们就可以得到从数组的后面往前到第i个位置,有最大的子数组和为
max_r[i] - 接下来我们就要从数组前面往后面考虑每个可能的位置i,即
for(int i=0;i<N-1;++i)我们要从位置i(包括i)前面来寻找一个尽可能大的子数组和,即cur_l=max(cur_l+a[i],0) - 为什么要用0去比较,因为题目还说了,我们可以不翻转,那要是
cur_l+a[i]<0你会选择要吗,我们肯定不要的 - 因为我们至少要>=0的贡献,而不要负贡献。不然和后面要翻转过来的数组一组合,还把不翻转时候的值还拉低了,肯定不要
- 最后一步就是综合考虑了,即
ans=max(ans,cur_l+max_r[i+1]) - 等遍历完后,直接输出答案
ans。即可!
到这里我们的思路以及对应的伪代码都已经出来了: 1~4步的思路用代码表示即:
int cur_r=data_array[N-1];
max_r[N-1]=data_array[N-1];
for(int i=N-2;i>=0;--i){
cur_r=Math.max(data_array[i],cur_r+data_array[i]);
max_r[i]=Math.max(max_r[i+1],cur_r);
}
5~8的思路用代码表示即:
int ans=max_r[0];
int cur_l=0;
for(int i=0;i<N-1;++i){
cur_l=Math.max(cur_l+data_array[i],0);
ans=Math.max(ans,cur_l+max_r[i+1]);
}
最终的代码即:
import java.util.Arrays;
public class Main {
public static int solution(int N, int[] data_array) {
int[] max_r=new int[N];
int cur_r=data_array[N-1];
max_r[N-1]=data_array[N-1];
for(int i=N-2;i>=0;--i){
cur_r=Math.max(data_array[i],cur_r+data_array[i]);
max_r[i]=Math.max(max_r[i+1],cur_r);
}
int ans=max_r[0];
int cur_l=0;
for(int i=0;i<N-1;++i){
cur_l=Math.max(cur_l+data_array[i],0);
ans=Math.max(ans,cur_l+max_r[i+1]);
}
return ans;
}
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循环多优雅~~~--->多痛苦。。。 所以本题的时间复杂度从O()到O()再到O(n),已经快了很多了~