求一组子数组的和
Find sum of an array of subarrays
这是2017年谷歌亚太地区的一个问题。问题D: Sum的总和
Alice给她的朋友Bob一个N个正整数的数组,从1到N。她向Bob提出了许多问题,如"这两个索引之间的数字之和是多少?"但是鲍勃解决这个问题太容易了。Alice取她的数组并找到它的所有N*(N+1)/2个非空子数组。她找到每个子数组的和,然后对这些值进行排序(以非递减顺序)以创建一个新的数组,索引从1到N*(N+1)/2。例如,对于初始数组[2,3,2],Alice将生成子数组[2],[3],[2],[2,3],[3,2]和[2,3,2](注意,例如[2,2]不是子数组)。然后,她会取这些和——2,3,2,5,5,7——并对它们进行排序,得到一个新的数组[2,2,3,5,5,7]。Alice给了Bob一个初始数组,以及Q个形式为"新数组中从索引Li到Ri的数字之和是多少?"的查询。现在鲍勃有麻烦了!你能帮帮他吗?
对于大型数据集,直接的解决方案即使在c++中也太低效了。有没有更有效的方法来解决这个问题?
目前我正在通过这个for循环来构造最终的数组:
multiset<int> sums;
long long int temp = 0;
for (long long int len = 1; len <= n; ++len)
{
for (int start = 0; start+len <= n; ++start)
{
temp = 0;
for (int i = 0; i < len; ++i)
{
temp += arr[start + i]; //arr stores the original array of n digits
}
sums.insert(temp);
}
}
<罢工> p。S:我现在的实现是O(n^5)吗?我的错误,我现在可以看到它是O(n^3)。谢谢你!编辑:到目前为止的答案很有帮助,但对于涉及n = 200000项的大型数据集,似乎任何预先计算整个子数组数组的解决方案都太昂贵了。所有提交的解决方案似乎都没有计算子数组的整个数组罢工>
如评论中所述,您的解决方案是O(N^3),计算为O(N^2)乘以O(N)和在multiset中插入(与O(N)相比,您可以忽略它,参见此答案的底部)。
但是交换你的前两个循环,你在做完全相同的N*(N+1)/2求和和插入:
for (int start = 0; start < n; ++start)
{
for (long long int len = 1; start + len <= n; ++len)
{
temp = 0;
for (int i = 0; i < len; ++i)
{
temp += arr[start + i]; //arr stores the original array of n digits
}
sums.insert(temp);
}
}
现在如果你看一下你的temp
和,很明显你在做冗余的工作。从start + 1
求和到start + 1
,然后从start + 1
求和到start + 2
,然后从start + 1
求和到start + 3
,依此类推。对于每个新的len
,计算的和是len
的前一个值加上一项。因此,你可以删除这个内部循环:
for (int start = 0; start < n; ++start)
{
temp = 0;
for (long long int len = 1; start + len <= n; ++len)
{
temp += arr[start + len]; //arr stores the original array of n digits
sums.insert(temp);
}
}
在N*(N+1)/2中生成了一组值。当然,使用multiset可以隐藏数据排序,但插入通常需要花费log(sums.size())
。
单独排序,因为对大小为S的集合排序需要S * log(S),所以N*(N+1)/2 * log ( N*(N+1)/2 )
的开销(刚好)小于N*(N+1) * log((N+1)/sqrt(2))
。
注意,因为你有正整数,你用内部循环生成的每一组len
整数都已经排序了,所以也许你可以用它们来做一些聪明的事情来加速排序。这也是multiset根据cplusplus.com所做的:
如果插入N个元素,一般为Nlog(size+N),但如果元素已经按照容器使用的相同排序标准排序,则为线性大小+N。
做了一点搜索,我发现了这个,我希望它会有用
https://www.quora.com/how可以-问题- d -总结- -总结-圆- e - - -谷歌亚太区-测试- 2016 -是-解决- - - - - - - -大型数据集
我能想到的最简洁有效的方法是:
std::vector<int> in{ 2, 3, 2 };
std::vector<int> out(in.size()*(in.size()+1)/2);
auto out_it = out.begin();
for (size_t i = 0; i < in.size() ; ++i) {
out_it=std::partial_sum(in.begin()+i, in.end(), out_it);
}
std::sort(out.begin(), out.end());
除了复杂性的考虑(这个解决方案是-我相信- O(n^2 * log(n)),因为你排序的数组有O(n^2)项),你应该避免动态内存分配和指针追逐像瘟疫(这两者都是std::multi_set
的固有部分)。
我的Python 3版本如下。
我没有测试所有的测试用例,但这只是一个实现的想法:
from functools import reduce
import itertools
stuff = [2,3,2]
temp = []
for L in range(1, len(stuff)+1):
for subset in itertools.combinations(stuff, L):
if len(subset) > 1:
if all(subset[0] == x for x in subset):
continue
print(subset)
temp.append(reduce(lambda x,y: x+y, subset))
temp = sorted(temp)
print(temp)
print("all sum : ", reduce(lambda x,y: x+y, temp))
- 我的字符串数组一次打印出前两个字符串
- 用最少的代码行数替换c++中的一组字符
- 如何检查cin是否与数组中的一组数字匹配
- 在字符数组中存储和恢复一组单词
- 生成一组随机的 x,y,z 数,它们之间和定义的限制之间具有最小差异
- 将 constexpr 数组扩展为一组非类型模板参数
- 我如何拥有一个在 c++ 中具有一组坐标的数组
- 设置数组一次索引很多?复合文字
- 将逗号添加到存储在数组中的一组字符串中
- 按变量数组中的列将一组整数从文本文件读入
- 如何在 C(首选)/C++ 中按顺序将一组 1D 数组传递给函数
- 在行和列中打印数组(一维数组)
- 家庭作业:一组位中的快速操作(表示为字符数组)
- 如何检查一组字符是否包含在C++的字符数组中
- 一组给定直线中的平行直线数
- 一组数组添加到一个新数组
- c++指针从一组数组
- 如何找到一组数组的最大值
- 我想得到一组唯一的n*n数组,这些数组在c++中的随机位置只包括0或1
- 求一组子数组的和