【问题标题】:Using a map to find subarray with given sum (with negative numbers)使用地图查找具有给定总和的子数组(带负数)
【发布时间】:2017-01-12 07:38:25
【问题描述】:

考虑以下问题陈述:

给定一个未排序的整数数组,找到一个与给定数字相加的子数组。如果有多个以 sum 为给定数字的子数组,则打印其中任何一个。

Examples:

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

Input: arr[] = {10, 2, -2, -20, 10}, sum = -10
Ouptut: Sum found between indexes 0 to 3

Input: arr[] = {-10, 0, 2, -2, -20, 10}, sum = 20
Ouptut: No subarray with given sum exists

在这个site 上,建议使用以下线性时间解决方案,在算法遍历数组时使用映射来存储当前子集的总和:

// Function to print subarray with sum as given sum
void subArraySum(int arr[], int n, int sum)
{
    // create an empty map
    unordered_map<int, int> map;

    // Maintains sum of elements so far
    int curr_sum = 0;

    for (int i = 0; i < n; i++)
    {
        // add current element to curr_sum
        curr_sum = curr_sum + arr[i];

        // if curr_sum is equal to target sum
        // we found a subarray starting from index 0
        // and ending at index i
        if (curr_sum == sum)
        {
            cout << "Sum found between indexes "
                 << 0 << " to " << i << endl;
            return;
        }

        // If curr_sum - sum already exists in map
        // we have found a subarray with target sum
        if (map.find(curr_sum - sum) != map.end())
        {
            cout << "Sum found between indexes "
                 << map[curr_sum - sum] + 1
                 << " to " << i << endl;
            return;
        }

        map[curr_sum] = i;
    }

    // If we reach here, then no subarray exists
    cout << "No subarray with given sum exists";
}
// Driver program to test above function
int main()
{
    int arr[] = {10, 2, -2, -20, 10};
    int n = sizeof(arr)/sizeof(arr[0]);
    int sum = -10;

    subArraySum(arr, n, sum);

    return 0;
}

使用帖子中提供的测试用例,第二个 if 语句检查是否 current_sum - sum 从未输入。相反,总和被找到并打印在第一个 if 语句中。 所以这里有几点混淆:

1:在地图中查找current_sum-sum的目的是什么?

2:在什么情况下还要输入第二个if语句来放map来解决问题?

【问题讨论】:

    标签: c++ arrays algorithm


    【解决方案1】:

    有两种情况:

    1. 从索引 0 到 n 的总和是我们正在寻找的数字。 cur_sum 是所有索引的运行总和,因此只需检查该变量即可。

    2. 索引m 到n 的总和就是我们要查找的数字。如果是这种情况,那么存在一个 m 使得 (sum from 0 to n) 减去 (sum from 0 to m) 就是我们正在寻找的总和。所有这些中间和都存储在映射中,这就是我们寻找cur_sum - sum 的原因 - 如果该差异对应于某个部分和,那么我们就完成了。

      第二种情况的示例是您问题中的第一个测试用例 - 在 {1, 4, 20, 3, 10, 5} 中查找 33。在n==4,我们有cur_sum 和38。但是5 在地图中是前两个索引的总和。

    【讨论】:

      【解决方案2】:
          curr_sum = curr_sum + arr[i];
      

      这里:

      curr_sum 保存从 arr[0] 开始的所有条目的总和(直到 arr[i])

      if (curr_sum == sum)
      {
          cout << "Sum found between indexes "
               << 0 << " to " << i << endl;
          return;
      }
      

      这里:

      if 条件检查 curr_sum 是否等于给定的总和。请记住,curr_sum 保存从 arr[0] 开始的总和。

      因此,如果您的结果子数组的索引是 2 和 4,则上述条件是不够的。

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

      在那个例子中,

      当 i = 4 时,curr_sum 将为 38。但如果将 1 和 4 取出(arr[0] 和 arr[1] 是一个子数组),则得到 33。

          if (map.find(curr_sum - sum) != map.end())
          {
              cout << "Sum found between indexes "
                   << map[curr_sum - sum] + 1
                   << " to " << i << endl;
              return;
          }
      
          map[curr_sum] = i;
      

      上面的代码就是这样做的。

       map[curr_sum] = i;
      

      map 以子数组 sum(索引 0 和 i 之间的 arr 之和)作为键存储索引值 (i)。因此,例如,它将是:

      • 地图[1]=0
      • 地图[5]=1
      • 地图[25]=2
      • 地图[28]=3
      • 地图[38]=4

      这段代码:

          map.find(curr_sum - sum)
      

      搜索地图是否有带有键(curr_sum - sum)的条目。

      在我们的示例中,当 i = 4 时,curr_sum 将为 38,并且给定的 sum 将为 33。如果我们消除子数组 arr[0,2],我们得到 33。因此,map.find(curr_sum - sum) => map.find(38-33) 很成功,因为我们有入口 map[5] = 1。

      希望这能让你明白

      【讨论】:

      • 很好的解释
      【解决方案3】:

      如果数组中没有负整数,则不需要映射。在这种情况下,您可以只维护一个 start 变量,从 currSum 中减去 arr[start] 并在 currSum > sum 时将 start 递增 1。

      如果数组中可能有负整数,可以使用这种带有映射的方法。

      试试这个例子来理解解决方案:

      -5、2、10、20、3、8

      总和 = 33

      答案:在索引 2 到 4 之间找到总和

      【讨论】:

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