【发布时间】:2021-02-11 15:56:05
【问题描述】:
我正在尝试解决GeeksForGeeks question 如下:
计算将一个数组分成三个总和相等的连续部分的方法的数量:给定一个包含n 数字的数组,找出i 和j 这样的索引对的个数从0 到i-1 的元素之和等于从i 到j 的元素之和等于从j+1 到n-1 的元素之和。对于输入{1, 2, 3, 0, 3},输出为2(我们有索引:(0, 1), (2, 2) and (3, 4) and (0, 1), (2, 3) and (4 , 4))
代码如下:
// C++ program to count number of ways we can
// partition an array in three parts with equal
// sum.
#include<bits/stdc++.h>
using namespace std;
// binary search to find the number of required
// indices in suffix array. Returns index of
// first element which is greater than x.
int binarysearch(vector <int> &v, int x)
{
int low = 0, high = v.size()-1;
while (low <= high)
{
int mid = (low + high)/2;
if (v[mid] <= x)
low = mid + 1;
else if (v[mid] > x && v[mid-1] <= x)
return mid;
else if (v[mid] > x && mid == 0)
return mid;
else
high = mid-1;
}
return -1;
}
// function to calculate the number of ways to
// divide the array into three contiguous parts
int CountContiguousParts(int arr[] ,int n)
{
int count = 0; // initializing answer
// Creating and filling prefix array
int prefix[n];
prefix[0] = arr[0];
for (int i=1; i<n; i++)
prefix[i] = prefix[i-1] + arr[i];
// Total sum of elements is equal to last
// value in prefix array.
int total_sum = prefix[n-1];
// If sum of all the elements is not divisible
// by 3, we can't divide array in 3 parts of
// same sum.
if (total_sum%3 != 0)
return 0;
// Creating and filling suffix array
int suffix[n];
suffix[n-1] = arr[n-1];
for (int i=n-2; i>=0; i--)
suffix[i] = suffix[i+1] + arr[i];
//<------Don't understand why we are doing things below------------->
// Storing all indexes with suffix
// sum equal to total sum by 3.
vector <int> v;
for (int i=0; i<n; i++)
if (suffix[i] == total_sum/3)
v.push_back(i);
// Traversing the prefix array and
// doing binary search in above vector
for (int i=0; i<n; i++)
{
// We found a prefix with total_sum/3
if (prefix[i] == total_sum/3)
{
// Find first index in v[] which
// is greater than i+1.
int res = binarysearch(v, i+1);
if (res != -1)
count += v.size() - res;
}
}
return count;
}
// driver function
int main()
{
int arr[] = {1 , 2 , 3 , 0 , 3};
int n = sizeof(arr)/sizeof(arr[0]);
cout << CountContiguousParts(arr, n);
return 0;
}
我不遵循创建向量 v 背后的逻辑,该向量存储所有后缀总和等于 (total sum/3) 的索引,然后进行二分查找,返回大于 i+1 的第一个元素的索引。
对于给定的示例{1, 2, 3, 0, 3},前缀数组是{1, 3, 6, 6, 9},而后缀数组是{9, 8, 6, 3, 3}。所以按照上面的逻辑,对于前缀数组索引i=1处的3,我们在后缀数组索引i=3处找到3,并将v.size() - res添加到count,这就是我们的答案2 在这里。 但是,我不明白它的作用以及它如何为我们提供答案。
我想的是前缀数组中索引 i=1 处的 3,我们应该计算后缀中以 i+1 开头的 3 的出现次数数组并返回该计数。
有人可以详细说明上面的代码是做什么的吗?
【问题讨论】:
-
小心你在网上找到的代码。考虑:Why is “using namespace std;” considered bad practice?、Why should I not
#include <bits/stdc++.h>? 和 Why aren't variable-length arrays part of the C++ standard?。在尝试从这段代码中学习之前,你应该知道它不是标准的 C++ -
@largest_prime_is_463035818,是的,谢谢你的留言。