找到给定总和的子阵列

时间:2016-09-04 19:32:08

标签: c++ arrays algorithm

问题陈述是:

  

给定一个未排序的非负整数数组,找到一个连续的子数组,它会增加给定的数字。

Examples:

Input: arr[] = {1, 4, 20, 3, 10, 5}, sum = 33
Ouptut: Sum found between indexes 2 and 4

Input: arr[] = {1, 4, 0, 0, 3, 10, 5}, sum = 7
Ouptut: Sum found between indexes 1 and 4

Input: arr[] = {1, 4}, sum = 0
Output: No subarray found

根据对this post解决方案的解释,以下解决方案不适用于负数:

/* An efficient program to print subarray with sum as given sum */
#include<stdio.h>

/* Returns true if the there is a subarray of arr[] with sum equal to 'sum'
   otherwise returns false.  Also, prints the result */
int subArraySum(int arr[], int n, int sum)
{
    /* Initialize curr_sum as value of first element
       and starting point as 0 */
    int curr_sum = arr[0], start = 0, i;

    /* Add elements one by one to curr_sum and if the curr_sum exceeds the
       sum, then remove starting element */
    for (i = 1; i <= n; i++)
    {
        // If curr_sum exceeds the sum, then remove the starting elements
        while (curr_sum > sum && start < i-1)
        {
            curr_sum = curr_sum - arr[start];
            start++;
        }

        // If curr_sum becomes equal to sum, then return true
        if (curr_sum == sum)
        {
            printf ("Sum found between indexes %d and %d", start, i-1);
            return 1;
        }

        // Add this element to curr_sum
        if (i < n)
          curr_sum = curr_sum + arr[i];
    }

    // If we reach here, then no subarray
    printf("No subarray found");
    return 0;
}

我尝试考虑几种不同的输入情况,但我想不出输入数组会包含负数但不能产生正确输出的情况。这是一个带负数的输入数组:

int arr[] = { 15, 14, -2, 3, -5, 14};

哪个输入案例是指该解决方案不适用于负数的帖子?

4 个答案:

答案 0 :(得分:3)

这个解决方案依赖于这个事实,当我们删除一个元素时,我们的总和会减少,但负数会与这个假设相矛盾。

最简短的例子就是这样的例子 -1 5 2当我们查找总和为5的子数组时。操作如下:

add -1, sum = -1
add 5, sum = 4
add 2, sum = 6
remove -1, sum = 7
remove 5, sum = 2

我们已经到了列表的末尾,但我们还没有找到所需的子阵列。

答案 1 :(得分:1)

如果子阵列的开头和结尾之间的总和超过了它所寻找的总和,则算法将失败。如果子数组的最后一个或多个值为负,则会发生这种情况。

例如,

int arr[5] = { 1, 2, 7, -5, 0 };
subArraySum(arr, 5, 5);

将失败

答案 2 :(得分:0)

while循环检查当前总和,如果它超过目标总和,则删除start元素并继续下一个(优化)。添加负值会使总和变小,因此这种技术不起作用,因为添加元素增加总和(因此可能超过目标总和)的假设无效。

如果你想修改算法以便允许负值,也不可能进行优化,你必须检查每个元素的总和直到数组的末尾(一个O(n 2 < / sup>)算法)。

答案 3 :(得分:0)

int sum = 7;
int arr[] = {-2,5,5,-1,7};

-2 + 5 + 5 = 8;

此时算法假设我们通过删除-2来减少当前总和,但事实上,它将增加到10.这里正确的移动是将-1添加到混合并得到我们的解决方案,但算法错过了它。

对于正整数,我们再也不需要那个-2,因为算法表明当前的总和已经太高而且只会通过向右前进而变得更高。负值,这个假设不成立。