考虑以下问题陈述:
给定一个未排序的整数数组,找到一个添加到给定数字的子数组。如果有多个子数组,其中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上,建议使用以下线性时间解决方案,当算法迭代数组时,使用map来存储当前子集的总和:
// 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语句来将地图用于解决问题?
答案 0 :(得分:16)
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将索引值(i)与子数组sum(索引0和i之间的arr之和)存储为关键字。因此,对于该示例,它将是:
此代码:
map.find(curr_sum - sum)
在地图中搜索是否有带密钥的条目(curr_sum - sum)。
在我们的例子中,当i = 4时,curr_sum将是38,并且给定的总和将是33.如果我们消除子数组arr [0,2],我们得到33.因此,map.find(curr_sum - sum) =&GT; map.find(38-33)是一个命中,因为我们有入口图[5] = 1。
希望这能让你清楚
答案 1 :(得分:9)
有两种情况:
n
的总和是我们正在寻找的数字。 cur_sum
是所有索引的运行总和,因此只需检查该变量即可。从索引m
到n
的总和是我们正在寻找的数字。如果是这种情况,则存在m
,使得(从0到n
的总和)减去(从0到m
的总和)是我们正在寻找的总和对于。所有这些中间总和都存储在地图中,这就是为什么我们要查找cur_sum - sum
- 如果这个差异对应于某个部分总和,那么我们就完成了。
第二种情况的一个例子是你问题中的第一个测试用例 - 在{1, 4, 20, 3, 10, 5}
中寻找33。在n==4
,我们cur_sum
38
。但5
在地图中是前两个指数的总和。
答案 2 :(得分:0)
如果数组中没有负整数,则不需要映射。在这种情况下你可以保持一个起始变量,从currSum中减去arr [start]并在currSum&gt;中增加1开始。总和。
如果数组中可能存在负整数,则可以使用带有映射的此方法。
尝试此示例以了解解决方案:
sum = 33
答案:索引2到4之间的总和