最大子数组(1)

题目:返回一个整数数组中最大子数组的和。

要求:输入一个整形数组,数组里有正数也有负数。 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。 求所有子数组的和的最大值。

设计思想:

  利用动态规划的思想,将该问题转化成计算包含当前数组元素以及不包含当前数组元素的子数组之间的较大者,并向前递推,最后变成计算第一个元素和0之间的较大者,从而解决了该问题。

源代码:

1 //计算一列数组中最大子数组之和,李青,胡金辉
 2 #include<iostream>
 3 using namespace std;
 4 #define max(x,y)  ( x>y?x:y )
 5 int main()
 6 {
 7     int i,length=0,list[1000];//定义循环变量、数组长度、数组
 8     int sum1;//记录包含当前数组元素的最大子数组之和
 9     int sum2;//记录不包含当前数组元素的最大子数组之和
10     cout << "请输入数组元素:" << endl;
11         while ((cin >> list[length++] ) && getchar() != '\n');
12         cout << "你输入了" << length << "个数" << endl;
13     
14     sum1 = list[0];
15     sum2 = 0;
16     for (i = 1; i < length; i++)
17     {
18         sum2 = max(sum2, sum1);
19         sum1 = max(sum1 + list[i], list[i] );
20     }
21     sum1 = max(sum2, sum1);
22     cout << "你输入的数组中最大子数组的值为:"<<sum1<<endl;
23     return 0;
24 }

结果截图:

 

 

总结:

  本次实验主要运用到了动态规划的思想,一开始并不是太清楚该思想是什么意思,后来在老师的解释下明白了,最后写出了程序,总的来说这次还是有很大收获的。

项目计划总结:

日期/任务听课编程阅读相关书籍网上查找资料日总计
周一100201010140
周二 30 1040
周三 1003020150
周四10030  130
周五 30 2050
周六 3030 60
周日     
周总结2002407060570

 

时间记录日志

日期开始时间结束时间中断时间净时间活动备注
3/2114:0015:5010100听课软件工程上课
 16:0016:20020编程 
 16:3016:40010阅读相关书籍《构建之法》
 17:0017:10010网上查找资料 
3/2219:0019:30030编程 
 19:4019:50010网上查找资料 
3/2314:0016:0020100编程 
 16:3017:00030阅读相关书籍《梦断代码》
 17:1017:30020网上查找资料 
3/2414:0015:5010100听课软件工程上课
 19:0019:30030编程 
3/2519:0019:30030编程 
 20:0020:20020网上查找资料 
3/269:009:30030编程 
 10:0010:30030阅读相关书籍《构建之法》

 缺陷记录日志:

日期编号类型引入阶段排除阶段修复时间备注
3/22120编码编译1min未定义变量sum2
3/25220编码编译1min循环嵌套输出错误

 

结对开发伙伴:李青  http://www.cnblogs.com/liqing1

工作照:

转载于:https://www.cnblogs.com/hujinhui/p/5323377.html

### 最大子数组和算法的实现 最大子数组和问题的目标是找到一个数组中和最大的连续子数组。该问题在算法领域中具有重要意义,尤其在动态规划和分治算法的应用中被广泛研究。 #### 方法1:蛮力法 蛮力法是最直观的解决方案,其基本思想是遍历所有可能的子数组,计算它们的和,并从中找出最大值。这种方法的时间复杂度为 $O(n^2)$,对于较小的数组规模是可行的,但对于较大的数组则效率较低。 以下是C语言实现: ```c #include <stdio.h> int maxSubArray1(int a[], int n) { int maxSum = 0; int i, j; for (i = 0; i < n; i++) { int currentSum = 0; for (j = i; j < n; j++) { currentSum += a[j]; if (currentSum > maxSum) { maxSum = currentSum; } } } return maxSum; } int main() { int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("最大子数组的和为: %d\n", maxSubArray1(arr, n)); return 0; } ``` #### 方法2:动态规划法 动态规划法是解决最大子数组和问题的经典方法,其时间复杂度为 $O(n)$,效率显著优于蛮力法。其核心思想是维护一个当前子数组的和,如果当前子数组的和小于0,则丢弃之前的子数组并重新开始计算。 以下是C语言实现: ```c #include <stdio.h> int maxSubArray2(int a[], int n) { int maxSum = a[0]; int currentSum = a[0]; for (int i = 1; i < n; i++) { currentSum = (currentSum + a[i] > a[i]) ? currentSum + a[i] : a[i]; maxSum = (currentSum > maxSum) ? currentSum : maxSum; } return maxSum; } int main() { int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("最大子数组的和为: %d\n", maxSubArray2(arr, n)); return 0; } ``` #### 方法3:分治法 分治法将数组分为左右两部分,分别求解左半部分和右半部分的最大子数组和,同时考虑跨越中间的最大子数组和。这种方法的时间复杂度为 $O(n \log n)$,适合大规模数据的处理。 以下是C语言实现: ```c #include <stdio.h> // 求三者中的最大值 int max(int a, int b, int c) { return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } // 求跨越中间的最大子数组和 int maxCrossingSum(int a[], int left, int mid, int right) { int sum = 0; int leftSum = -999999; for (int i = mid; i >= left; i--) { sum += a[i]; if (sum > leftSum) { leftSum = sum; } } sum = 0; int rightSum = -999999; for (int i = mid + 1; i <= right; i++) { sum += a[i]; if (sum > rightSum) { rightSum = sum; } } return leftSum + rightSum; } // 分治法主函数 int maxSubArray3(int a[], int left, int right) { if (left == right) { return a[left]; } int mid = (left + right) / 2; int leftMax = maxSubArray3(a, left, mid); int rightMax = maxSubArray3(a, mid + 1, right); int crossMax = maxCrossingSum(a, left, mid, right); return max(leftMax, rightMax, crossMax); } int main() { int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("最大子数组的和为: %d\n", maxSubArray3(arr, 0, n - 1)); return 0; } ``` ### 总结 - **蛮力法**:简单直观,但效率较低,时间复杂度为 $O(n^2)$。 - **动态规划法**:高效且简洁,时间复杂度为 $O(n)$。 - **分治法**:适用于大规模数据,时间复杂度为 $O(n \log n)$,但实现较复杂。 根据具体需求和数据规模,可以选择合适的算法实现最大子数组和的求解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值