如何计算一个整形数组里的连续元素和的最大值?

本文介绍了一种高效算法来寻找整型数组中连续元素和的最大值,通过引入中间函数MaxX[i],该算法的时间复杂度为O(N),避免了不必要的重复计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自 http://www.yl1001.com/ask/41004/question/5461393293384111.htm

例:{9, -12, 120, 8, -20, 100, 30, -89, 20} 结果是{120, 8 , -20, 100, 30}的和最大,为 238 函数声明: int max_sum(int *array, int array_len);请计算一个整形数组里的连续元素和的最大值,求方法~将问题转变转变,其实也可以考虑一下,如何求一个整形数组里的非连续元素和的最大值~


这是一个比较典型的说明算法效率差异的题目。最笨也是最简单的算法的效率是O(N*N),如果注意到结果的可重复利用,可以实现O(N*LogN)的算法,但是最优的计算复杂度是O(N)。无论如何至少要遍历一遍整个数组,所以不可能有O(1)的实现方法。上面大家给出了很多的算法,liukun提出的分治的方法,这个问题不应该是分治问题,用分治的方法只会把问题搞复杂,它的计算复杂度应该是O(N*LogN)。唐仕强和黄文彬给出的都是O(N)的解决方案,没有太仔细看,但我想结果都应该是对的,有问题也是对一些特殊情况的处理上,譬如对全部是负数的特殊情况的考虑,但是这些不影响整个算法的解体思路。问题的关键是如何自然地写出O(N)的算法。下面给出一个思考该算法的思路。

首先将问题描述形式化如下:
1 记数组为 A,其元素从0到n-1。
2 数组A的子数组记为A[i,j],表示[i,j]闭区间区域的子数组。
3 子数组A[i,j]的和记为SA[i,j]
4 问题目标是寻找S[i,j]的最大值,记为MaxS[0,n-1]
分析问题内在的性质,引入一个中间函数,
X[i]表示所有以i为右边界的子数组的集合,即{A[0,i],A[1,i]...A[i, i]}
MaxX[i]= max(SA[j,i]),其中 j=[0, i],表示X[i]集合中最大的子数组的和。
MaxX[i]记录的是以i为右端点的最大子数组和。它显然符合以下递推公示,
MaxX[i]= Max[i-1]+A[i](Max[i-1]>= 0)
= A[i] (Max[i-1]< 0)
所以MaxX[i]可以很容易计算,而最终的目标结果就是MaxX[i]的最大值
MaxS[0, n-1] = max(MaxX[i]),其中i=[0, n-1];

根据以上的分析,算法的代码实现就会比较自然流畅,java实现如下:

int sum = A[0];
int left = 0;
int leftOfMax = 0;
int rightOfMax = 0;
int maxSum = A[0];
for(int i = 1; i<A.length; i++){
   if(sum < 0){
       sum = A[i];
       left = i;
   }else{
       sum = sum + A[i];
   }

   if(sum > maxSum){
       maxSum = sum;
       leftOfMax = left;
       rightOfMax = i;
   }
}

//这里maxSum为目标结果,其所对应的子数组为A[leftOfMax, rightOfMax].

在Java中,要找到一个长度大于5的整型数组中平均值最大的连续三个整数,可以按照以下步骤操作: 1. 首先,我们需要遍历整个数组,同时维护两个窗口大小为3的滑动数组,分别称为`windowA``windowB`。其中,`windowA`用于计算当前三个数的平均值,而`windowB`会每次向右移动一位,替换掉旧的元素并更新平均值。 2. 初始化这两个窗口,将前三个数添加到`windowA`中,同时计算它们的平均值(初始`averageA`)。 3. 从数组第4个元素开始循环,对于每个元素`num`,做以下操作: a. 计算`windowB`的新平均值(`newAverageB`),如果`windowA`的平均值小于`newAverageB`,则说明`windowB`中的连续三个数平均值更大。 b. 更新`windowA`的最后一个元素(移除最左边的元素,并将新元素加入),并计算新的平均值(`newAverageA`)。 c. 如果`newAverageA`比`averageB`大,则更新全局的最大平均值对应的起始结束索引。 4. 循环结束后,你得到的起始索引、结束索引以及最大平均值对应的连续三个数就是所求。 以下是伪代码示例: ```java int[] arr = ...; // 假设arr是一个大于5的整型数组 int maxAvg = Integer.MIN_VALUE; int startIndex = -1, endIndex = -1; // 初始化滑动窗口 for (int i = 0; i < 3; i++) { averageA += arr[i]; } // 迭代数组 for (int i = 3; i < arr.length; i++) { averageA = (averageA - arr[i - 3]) + arr[i]; // 更新窗口A averageB = (averageB * 2 + arr[i]) / 3; // 更新窗口B if (averageA > maxAvg) { maxAvg = averageA; startIndex = i - 2; endIndex = i; } if (i >= 2 && averageB > maxAvg) { maxAvg = averageB; startIndex = i - 1; endIndex = i; } } // 返回结果(如果存在) if (startIndex != -1 && endIndex != -1) { System.out.println("最大平均值: " + maxAvg); System.out.println("连续三个数: [" + arr[startIndex] + ", " + arr[startIndex + 1] + ", " + arr[endIndex] + "]"); } else { System.out.println("数组太小,无法找到满足条件的连续三个数字"); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值