【问题标题】:Finding subarray with given sum查找具有给定总和的子数组
【发布时间】:2017-01-12 05:49:16
【问题描述】:

问题陈述是:

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

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};

当帖子说解决方案不适用于负数时,指的是哪些输入案例?

【问题讨论】:

  • 调试器。使用调试器。当您执行程序时,调试器将帮助您逐句显示变量中的值。

标签: c++ arrays algorithm


【解决方案1】:

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

最短的例子是这样的情况 -1 5 2当我们在寻找总和为5的子数组时,操作如下:

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

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

【讨论】:

    【解决方案2】:

    如果子数组的开始和结束之间的总和超过它正在寻找的总数,则该算法将失败。如果子数组的最后一个或多个值是负数,就会发生这种情况。

    例如,

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

    会失败

    【讨论】:

      【解决方案3】:

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

      如果您想修改算法以允许负值,则无法进行优化,并且您必须检查从每个元素到数组末尾的总和(a O(n2) 算法)。

      【讨论】:

      • 其实,如果你使用哈希表,你仍然可以做 O(n)
      • 哈希表在这里?如何以及为什么?数组是有序的。而且我不确定创建哈希表、将其绑定到输入表并销毁它的额外开销。你能详细说明一下吗?
      【解决方案4】:
      int sum = 7;
      int arr[] = {-2,5,5,-1,7};
      

      -2 + 5 + 5 = 8;

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-12
        • 2013-02-03
        • 2016-04-03
        • 2014-11-15
        • 2015-07-27
        • 2017-02-20
        • 1970-01-01
        • 2012-12-10
        相关资源
        最近更新 更多