简体   繁体   English

求和 < k 的 n 个连续数的最大和

[英]Finding the max sum of n consecutive numbers where sum < k

I am given an array and asked to find the maximum possible sum of n consecutive numbers, where the maximum sum is less than a given value k .我得到一个数组,并被要求找到n个连续数字的最大可能和,其中最大和小于给定值k For example:例如:

array = {1, 3, 1, 2, 3, 4, 1}
k = 7

Here, the answer must be 6 , because the max sum that we can obtain that is less than 7 is: arr[1] + arr[2] + arr[3] = 3 + 1 + 2 = 6 How can I write an algorithm to find such a value?在这里,答案必须是6 ,因为我们可以获得的小于 7的最大和是: arr[1] + arr[2] + arr[3] = 3 + 1 + 2 = 6我怎样才能写出找到这样一个值的算法?

(I have done it with a nested for loop, but it takes too much time, is there any other way to make this program work?) (我已经用嵌套for循环完成了,但是它花费了太多时间,有没有其他方法可以使这个程序工作?)

Basic Foundation基础基础

First off, I'd suggest you read up a bit more about time complexity.首先,我建议您阅读更多有关时间复杂度的信息。 There are enough good resources out there, and Complexity Theory is one of them.那里有足够好的资源,复杂性理论就是其中之一。 This should help you understand why your solution is not fast enough.这应该可以帮助您理解为什么您的解决方案不够快。

O(n^3) Solution O(n^3) 解

A brute-force approach is to check all possible subarrays, by iterating over the start and end points of the subarray, and adding up all elements in between.一种蛮力方法是检查所有可能的子数组,方法是遍历子数组的起点和终点,并将其间的所有元素相加。

Given an array arr of size n , the way to do that would be as follows:给定一个大小为n的数组arr ,方法如下:

for (int l = 0; l < n; ++l) {
    for (int r = l; r < n; ++r) {
        long sum = 0;
        for (int pos = l; pos <= r; ++pos) {
            sum += arr[pos];
        }
        if (sum < k)
            max = Math.max(max, sum);
    }
}

The final answer is stored in max .最终答案存储在max中。

O(n^2) Solution O(n^2) 解

A faster solution would eliminate the third loop by making use of prefix sums .更快的解决方案是通过使用前缀 sum来消除第三个循环。 This can be done as follows, with the help of an auxiliary array preSum of the same size as the main array, where preSum[i] stores the sum of the first i elements:这可以通过与主数组大小相同的辅助数组preSum来完成,其中preSum[i]存储前i个元素的总和:

preSum[0] = arr[0];
for (int i = 1; i < n; ++i)
    preSum[i] = preSum[i - 1] + arr[i];
for (int l = 0; l < n; ++l) {
    for (int r = l; r < n; ++r) {
        long sum = preSum[r];
        if (l > 0)
            sum -= preSum[l - 1];
        if (sum < k)
            max = Math.max(max, sum);
    }
}

O(n) solution O(n) 解

The most efficient solution to this problem uses a sliding window / two-pointer approach.此问题最有效的解决方案是使用滑动 window /双指针方法。 Note that we assume that negative numbers are not allowed.请注意,我们假设不允许使用负数。

We start with both l and r at the beginning of the array.我们从数组开头的lr开始。 There are two possible cases at every stage:每个阶段都有两种可能的情况:

  1. Sum of the current subarray <k : We can be hopeful and try to add more elements to the subarray.当前子数组的总和<k :我们可以抱有希望并尝试向子数组添加更多元素。 We do this by moving r one step further to the right.为此,我们将r向右移动一步。
  2. Sum of the current subarray >=k : We need to remove some elements to make the sum satisfy the given constraint.当前子数组的总和>=k :我们需要删除一些元素以使总和满足给定的约束。 This can be done by moving l one step to the right.这可以通过将l向右移动一步来完成。

This is repeated till we hit we need to increment r , but have reached the end of the array.这一直重复,直到我们需要增加r ,但已经到达数组的末尾。 The code looks something like this:代码看起来像这样:

long max = 0;
int l = 0;
int r = 0;
long sum = arr[0];
    while (true) {
    if (sum >= k) {
        sum -= arr[l];
        ++l;
    } else {
        if (r == n - 1)
            break;
        else {
            ++r;
            sum += arr[r];
        }
    }
    if (sum < k)
        max = Math.max(max, sum);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM