版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29963323/article/details/78449516
今天要把算法联系提到日程上了,就从最简单的算法开始学习。介绍一下求解的过程。
首先问题是这样的,给定数组a[1…n],求最大子数组和,即找出1<=i<=j<=n,使a[i]+a[i+1]+…+a[j]最大,求最大子数组和。
题意:int[] arr = {-2,-1,-3,4,-1,2,1,-5,4}; 比如有这样一个数组,求这个数组的子数组加起来的值最大。这里给出三种解法,时间复杂度分别为 O(N^3) O(N^2) O(N),由简单的思路开始,第一种解法,暴力,全部枚举出来:
暴力:
int max = 0;
int[] arr = {-2,-1,-3,4,-1,2,1,-5,4};
for(int i=0;i<arr.length;i++) {
for(int j=0;j<arr.length;j++) {
int sum = 0;
for(int k=i;k<j;k++) {
sum = sum+(arr[k]);
}
if(max < sum) {
max = sum;
}
}
}
System.out.println(max);
这里求解这道题用了三层循环,我们主要看最内层循环,这里i和j分别是起始位置和终止位置,遍历出每个sum,然后找到最大的那个,就是数组子数组加起来的值最大。显然,这里的时间复杂度为O(N^3),虽然能算出结果,为6,但是明显是超时的,下面给出第二个解法,发最内层循环去掉。
优化枚举:
int max = 0;
int[] arr = {-2,-1,-3,4,-1,2,1,-5,4};
for(int i=0;i<arr.length;i++) {
int sum = 0;
for(int j=i+1;j<arr.length;j++) {
sum = sum+(arr[j]);
if(max < sum) {
max = sum;
}
}
}
System.out.println(max);
}
}
这里,j的值肯定比i的值大,因为要在一个区间内。所以这是j是从i+1开始的,枚举出每个区间的值,这样最后一个数之前的全部和就只算了一遍,这就简化了,就能算出i到j区间内相加得到的最大值。显然,这个事件复杂度为O(N^2),在OJ系统中,也是超时的,不能通过的,下面给出一个算法,事件复杂度为O(N)的
贪心:
起初,这个解法并不知道叫贪心。是这样的,我们可以把从i到j区间相加得到最大转化为 前j个数相加得到的值减去前i个数相加得到的值,找到最大值就可以了。这样就变成让j固定不动,找出前i个值相加得到的最小值就可以了。我们定义三个变量 si:前i个值得和,sj:前j个值得和,minSi:前i个值最小的和。
int max = 0;
int si = 0;//前i个值得和
int sj = 0;//前j个值得和
int minSi = 0;//前i个值最小的值
int[] arr = {-2,-1,-3,4,-1,2,1,-5,4};
//固定下来
for(int i=0;i<arr.length;i++) {
sj += arr[i];//前j个值
if(minSi > si) {
minSi = si;
}
//前j个值减去前i个值最小和
if(sj - minSi > max) {
max = sj - minSi;
}
si+=arr[i];
}
System.out.println(max);
这样的想法还好想点。若想变成网上的一些贪心的算法,比如
int[] arr = {-2,-1,-3,4,-1,2,1,-5,4};
int ans = -34324324;
int sum = 0;//si - minSi
for(int i=0;i<arr.length;i++) {
sum += arr[i];
if(sum > ans) {
ans = sum;
}
if((sum)< 0) {
sum = 0;
}
}
System.out.println(ans);
这里的代码就是由这段代码上面的转化过来的。我们可以采用代码替换,用 sum = si-minSi,si和si是一样的,这样一步步替换掉就可以了。最后替换是,sum与minSi无关,于是sum就是随着si的变化而变化的,所以si+=arr[i] 可以转化为 sum+=arr[i].还有先加后加问题,把sum+=arr[i]放在后面和放在前面的问题,sum+arr[i]变为sum等等。转化之后就能看出来了。
此文章不建议作为参考,仅供自己查阅。比较乱。。。。。作为笔记看。。。。。