如何找到数组n
连续数的最大总和?例如,如果我们的数组是{2,5,3,4,6}
和n == 2
,则输出应为10
(即6 + 4
)。
我能够为数组大小的小值和n
的小值获得正确的逻辑。但是当数组大小和n太大,大约10 5 时,我的代码需要花费很多时间。请建议优化方法。
我的代码剪断了:
for(int i = 0; i <= n - h; i++) {
int count = 0;
for(int k = i; k < i + h; k++) {
count = count + arr[k];
}
if(i == 0) {
ans[z] = count;
} else if(i != 0) {
if(count < ans[z]) {
ans[z] = count;
}
}
count = 0;
}
答案 0 :(得分:5)
这是我的想法:将数组从0遍历到(数组长度 - N),并使用以下表达式确定下一个N项的总和:
下一个N项目的总和=前一个总和 - 前一个子阵列中的第一个项目+下一个子阵列中的最后一个项目
实施例:
数组= {2,5,3,4,6}
当i = 0时,sum =(2 + 5)= 7,max sum = 7
当i = 1时,sum = 7-2 + 3 = 8,因为8> 1。 7,所以max sum = 8
当i = 2时,sum = 8 - 5 + 4 = 7,因为7
当i = 3时,sum = 7-3 + 6 = 10,因为10> 8,所以max sum = 10
下面的是c#
中的示例代码static int GetLargestSum(int[] array, int n)
{
int largestSum = 0;
int previousSum = 0;
for (int i = 0; i <= array.Length - n; i++)
{
if (i == 0)
{
for (int j = 0; j < n; j++)
{
largestSum += array[j];
}
previousSum = largestSum;
}
else
{
int currentSum = previousSum - array[i - 1] + array[i + n - 1];
if (currentSum > largestSum)
{
largestSum = currentSum;
}
previousSum = currentSum;
}
}
return largestSum;
}
答案 1 :(得分:1)
使用Java 8。
int[] numArr = {1,3,5,6,7,12,14,2,3,4};
List<Integer> intList = Arrays.stream(numArr).boxed().collect(Collectors.toList());
List<Integer> intSumList = new ArrayList<>();
for(int i=0; i<=numArr.length-3; i++)
{
int intSum = intList.stream().skip(i).limit(3).mapToInt(Integer::intValue).sum();
intSumList.add(Integer.valueOf(intSum));
}
int maxConsecutiveSum = intSumList.stream().reduce(Integer::max).get();
System.out.println("Max sum using 3 consecutive integers :"+maxConsecutiveSum);
答案 2 :(得分:0)
您的技术可能的主要改进是滑动窗口。整数加法有一个倒数减法。这使得可以从总和中删除元素并添加新元素,而不是从头开始重新计算。 (Terryfkjc's answer demonstrates this)。
正如Terryfkjc评论他的回答,那就是有线程级并行性。您可以让不同的线程检查数组的不同部分。如果滑动窗口的大小超过数组大小的一半,那么应该对第一个n
进行求和。当n
大约是数组大小的一半时,在线程之间划分工作是最棘手的。更大,它不能滑到目前为止。更小,大部分工作只是滑动。
如果您使用矢量指令定位CPU,我们可以使用SIMD轻松地对第一个w
(窗口大小/宽度)元素的初始总和进行矢量化。例如,使用x86 SSE(C / C ++内在函数):
#include <immintrin.h>
const __m128i *array_vec = (__m128i*)array;
__m128i sums = _mm_loadu_si128(array_vec); // or start with _mm_setzero_si128()
// careful to get the loop start/end and increment correct,
// whether you count by vectors (i++) or by elements (i+=4)
// You may need a scalar cleanup at the end if window width isn't a multiple of the vector width
for (int i=1; i < width/4 ; i+=1) {
sums = _mm_add_epi32(sums, _mm_loadu_si128(array_vec+i));
// if you know the input is aligned, and you're going to compile without AVX/AVX2, then do:
// sums = _mm_add_epi32(sums, array_vec[i]);
}
__m128i hisums = _mm_bsrli_si128(sums, 8); // get the high 2 elements into the low 2 elements of a separate vector
sums = _mm_add_epi32(sums, hisums); // one step of horizontal merging.
hisums = _mm_bsrli_si128(sums, 4); // actually, pshufd would be faster for this, since it doesn't need a mov to preserve sums.
sums = _mm_add_epi32(sums, hisums);
int window_sum = _mm_cvtsi128_si32(sums); // get the low 32bit element
我认为不可能对滑动窗部件进行矢量化。我们无法有效地滑动4个单独的窗口,因为每个窗口(向量元素)都需要查看每个数组元素。
然而,如果我们对4/8/16不同的窗口大小(最好是连续的)感兴趣,那么我们可以用向量来做。因此,在每次循环迭代中,我们都有一个带有当前滑动窗口总和的向量。使用SSE4.1 pmaxsd
(对于带符号的32位整数),我们可以做
window_max = _mm_max_epi32(window_max, window_sums);
滑动窗口操作变为:添加{ a[i], a[i+1], a[i+2], a[i+3] }
,同时从所有4个向量元素中删除相同的数组元素。 (或者,广播要添加的元素,并减去不同元素的向量。)
__m128i add_elements = _mm_loadu_si128((__m128i*)&array[i]); // load i, i+1, etc.
__m128i sub_element = _mm_cvtsi32_si128(array[i-width-1]);
sub_element = _mm_shuffle_epi32(sub_element, 0); // broadcast the low element of the vector to the other positions.
// AVX2: use _mm_broadcastd_epi32
// AVX512 has a broadcast mode for memory references that can be used with most instructions. IDK how to use it with intrinsics.
__m128i diff = _mm_sub_epi32(add_elements, sub_element);
window_sums = _mm_add_epi32(window_sums, diff);
正确地获取循环开始/结束条件,并正确地计算最后几个元素,这始终是向量的挑战。
有关如何在x86上使用向量的更多信息,请参阅https://stackoverflow.com/tags/x86/info。
答案 3 :(得分:0)
使用滑动窗口,其中窗口大小为2
arr = [2,5,3,4,6];
sum = 0;
temp_sum = 0;
const add = (a,b) => a+b;
for(let i=0;i<arr.length-1;i++){
console.log(i, i+2,arr.slice(i,i+2));
temp_sum = add.apply(null, arr.slice(i,i+2));
if(sum < temp_sum){
sum = temp_sum;
}
}
console.log(sum);
答案 4 :(得分:0)
这是一个简短的快速解决方案:
s = 0
arrayMaxConsecutiveSum = (a, k) =>
Math.max(...
a.map(x => s += x - ~~a[~--k])
)
答案 5 :(得分:0)
function maxSubelementsSum(inputArray, count) {
let maxSum = 0;
for (let i = 0; i < count; i++) {
maxSum += inputArray[i];
}
let tempSum = maxSum;
for (let i = count; i < inputArray.length; i++) {
tempSum = tempSum + inputArray[i] - inputArray[i - count];
maxSum = Math.max(tempSum, maxSum);
}
return maxSum;
}
答案 6 :(得分:0)
def maxSubarraySum(array, noOfelements):
start = 0
sum = 0
nextElement = 1
maxSum = []
while noOfelements < len(array)+1:
for i in range(start, noOfelements):
sum += array[i]
maxSum.append(sum)
sum = 0
start = nextElement
nextElement += 1
noOfelements += 1
return max(maxSum) if maxSum else None
if __name__ == '__main__':
print(maxSubarraySum([-1, -2, -5, -3, -8, -1, -5], 4) == -11)
print(maxSubarraySum([1, -2, 5, 3, -8, 1, 5], 4) == 7)
print(maxSubarraySum([1, 2, 5, 3, 8, 1, 5], 4) == 18)
print(maxSubarraySum([1, 2, 5, 3, 8, 1, 5], 2) == 11)
print(maxSubarraySum([], 4) == None)
复杂度 = O(n*n) 这适用于所有给定的数组,包括负数。
答案 7 :(得分:0)
有很多方法可以解决这个问题。
到目前为止,我能想到的最优化的是 O(n)。
您可以遍历数组一次的地方。
我使用了滑动窗口模式来解决这个问题
这是解决方案背后的主要思想:
function maxSubarraySum(array, num){
let tempMax = 0
for(let i=0; i<num; i++){
tempMax += array[i]
}
let max = tempMax
for(i=1; i<array.length - (num-1); i++){
// Substract the element you are at from the max
// Add the element at the ith + num
// compare with the max and reinitialize
let subs = tempMax - array[i-1]
tempMax = subs + array[i + num - 1]
if(max < tempMax){
max = tempMax
}
}
return(max)
}
答案 8 :(得分:-1)
最简单的
A=list(map(int,input().split(" ")))
n=len(A)
max=0
for i in range(n-1):
if(A[i]+A[i+1]>max):
max=A[i]+A[i+1]
print(max)
答案 9 :(得分:-1)
简单地我们可以迭代数组并找到两个连续数字之和
let array = [2,5,3,4,6];
let sum=0;
let maxNumber = 0;
for(let i=0; i<array.length;i++){
sum = array[i] + array[i+1];
if(sum >= maxNumber){
maxNumber = sum;
}
}
console.log("max of two digit :", maxNumber);
答案 10 :(得分:-2)
我建议你首先使用mergesort对数组进行排序,其复杂时间为O(n log(n))然后你只需找到前n个连续数字,从较高的数字迭代数组到较低的一个保持当前连续数字的总和,这将花费复杂时间O(n)。问候