C语言求子数组相加的和最大,C语言强化(三)发现潜在规律——求子数组的最大和...

上一篇解答了在栈里面求最小值元素的问题,这一篇,来聊聊怎么找到数组中子数组的最大和。

通过这道题,你可以掌握

如何根据用户输入创建数组

如何在一连串数字中找到和最大的某一段连续数字子串

如何发现问题的潜在规律并利用这个规律设计算法,解决问题

8531fb35620bc296434e47a243cd9ff9.png

思路

连续数相加要最大,说明左右两边的数肯定不是负数,否则不可能最大

连续数序列中允许存在负数,前提是负数前面的一段正数相加要大于这个负数,否则两者抵消后,和会变小

算法

遍历数组

遇到正数,不断累加,遇到的第一个正数要记录下标

遇到负数,记录下标,把此下标减1和之前记录的正数的下标之间的数组作为一个可能最大数组,

与之前的可能最大数组比较,若变大,则取代!

判断累加的值与负数大小关系

如果累加值大于负数,则继续累加

如果累加值小于等于负数,舍弃此负数,向前移动,累加值清零

源代码

#include

#include

#include

#include

#include

using namespace std;

/**

输入一个整形数组,数组里有正数也有负数。

数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。要求时间复杂度为 O(n)。

例如输入的数组为 1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为 3, 10, -4, 7, 2,

因此输出为该子数组的和 18。

思路

连续数相加要最大,说明左右两边的数肯定不是负数

连续数序列中允许存在负数,前提是负数前面的一段正数相加要大于这个负数

算法:

遍历数组

遇到正数,不断累加,遇到的第一个正数要记录下标

遇到负数,记录下标,

把此下标减1和之前记录的正数的下标之间的数组作为一个可能最大数组,

与之前的可能最大数组比较,若变大,则取代!

判断累加的值与负数大小关系

如果累加值大于负数,则继续累加

如果累加值小于等于负数,舍弃此负数,向前移动,累加值清零

*/

void main()

{

//根据用户输入创建数组

vector oriArray;

int n=0,count=0;

string str;

bool endFlag=true;

while(endFlag){

cout<

cin>>str;

if(str=="e"){

endFlag=false;

}else{

stringstream(str)>> n;

oriArray.push_back(n);

count++;

}

}

cout<

for(int i =0;i

cout<

}

//求最大子数组

/**

add:累加值

ori:累加值的起始角标

max:最大和

maxOri:最大和子数组起始角标

maxEnd:最大和子数组结尾角标

*/

int add=0,ori=0,max=0,maxOri=0,maxEnd=0;

bool firstPos=true;

//遍历

for(int i =0;i

//遇到正数

if(oriArray[i]>=0){

add+=oriArray[i];//不断累加

if(firstPos){//遇到的第一个正数要记录下标

ori=i;

firstPos=false;

}

}else{

//遇到负数

//之与前的可能最大和比较,若变大,则取代!

if(add>max){

max=add;

maxOri=ori;

maxEnd=i-1;

}

/**

判断累加的值与负数大小关系

如果累加值大于负数,则继续累加

如果累加值小于等于负数,舍弃此负数,向前移动,累加值清零

*/

if(oriArray[i]+add>0){

add+=oriArray[i];

}else{

add=0;

if(i+1

ori=i+1;

}

}

}

//跳出循环后再判断一次

if(add>max){

max=add;

maxOri=ori;

maxEnd=oriArray.size()-1;

}

cout<

cout<

cout<

cout<

for(int i=maxOri;i>=maxOri&&i<=maxEnd;i++){

cout<

}

system("pause");

}运行图

1fc8c75292e1ba54879a50f3949a72c8.png

此题的关键在于发现最大和子数组的两端不能是负数这个规律。

做完之后在网上找了找类似的题目答案,发现有大神给出了更牛的解法,在此共享一下

思路2:

当前面的几个数,加起来后,b<0后,

把 b 重新赋值,置为下一个元素,b=a[i]。

当 b>sum,则更新 sum=b;

若 b

源代码2:

#include

#include

#include

#include

using namespace std;

/**

输入一个整形数组,数组里有正数也有负数。

数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。要求时间复杂度为 O(n)。

例如输入的数组为 1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为 3, 10, -4, 7, 2,

因此输出为该子数组的和 18。

思路

当前面的几个数,加起来后,b<0后,

把 b 重新赋值,置为下一个元素,b=a[i]。

当 b>sum,则更新 sum=b;

若 b

*/

int maxSum(int* a, int n)

{

int sum=0;

int b=0;

for(int i=0; i

{

if(b<=0) //前面的几个数,加起来后,b<0

b=a[i];//b 重新赋值

else

b+=a[i];//前面的几个数,加起来后,b>=0,继续累加

if(sum

sum=b;// b>sum,则更新 sum=b

}

return sum;

}

void main()

{

int a[10]={1,-8,6,3,-1,5,7,-2,0,1};

cout<

system("pause");

}

解法二之所以比解法一简练,在于他不仅仅意识到两端的数不能为负数,而且只要那一串的子数组相加小于0,就不可能是最大和子数组的一部分。

每个问题都有其发生的规律,设计算法的过程就是发现规律并加以利用的过程。

就好比打羽毛球,如果我发现只要我一回高远球,对手就放短球,那么我下次回完高远就直接冲到网前准备扑杀。

原文:http://blog.csdn.net/hzy38324/article/details/45190117

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值