对向量中的整数序列求和

Posted

技术标签:

【中文标题】对向量中的整数序列求和【英文标题】:Sum a sequence of integers in a vector 【发布时间】:2015-01-10 09:43:05 【问题描述】:

我有函数bool exists(int sum, vector<int>& vec) 它的作用是返回vec 中是否有任何等于sum 的数字序列。

例如

Vec = 140 80 90 180 70 sum = 300

函数返回true,因为序列140 90 70存在且等于300。

现在我有代码:

bool possible(int sum, vector<int> &vec)

do

    int s = 0;
    for (int i = 0; i < vec.size(); i++)
    
        s += vec.at(i);
        if (s == sum)
        
            return true;
        

    
while(next_permutation(vec.begin(), vec.end()));

return false;

即使矢量大小只有 20,它也可以工作,但需要的时间太长。

谁能帮我找到更好的方法?

【问题讨论】:

这个问题和subset sum一样难。 正如我所见,该任务需要大约 N!迭代。 20!是2,43*10^18,一般不会更快。 也许这会有所帮助。 geeksforgeeks.org/dynamic-programming-subset-sum-problem 你能对数字进行排序吗? 我已经回滚了这个问题,因为您将代码更改为不同的算法。 【参考方案1】:

有效

首先,它不太有效,除非vec 被排序为开头。否则,next_permutation(...) 将产生false 而不用尽所有可能性,可能会跳过找到正确解决方案的排列。

但即使矢量大小只有 20 也需要很长时间。

那是因为这是一个 O(N!) 解决方案。请注意,即使对于蛮力解决方案,N! 也是不必要的高,因为添加的顺序无关紧要。您只需要 O(2N) 即可尝试所有子集。

您可以通过对0/1 knapsack problem 使用伪多项式解决方案来做得更好。这个想法是创建一组所有可能的总和,直到所需的数字 N。从一个数字零开始这个集合。每次迭代产生另一个集合,其中包含上一次迭代的集合的所有元素,加上通过将列表中的数字添加到先前的每个总和产生的集合,将值限制为目标数字(即 300):

 0 
 0, 140  -- Added 0+140
 0, 80, 140, 220  -- Added 0+80, 140+80
 0, 80, 90, 140, 170, 220, 230  -- Added 0+90, 80+90, 140+90; 220+90 > 300, so it is not added
... // And so on

在此过程结束时,您将获得集合中所有可能的总和。现在您需要做的就是检查您的目标编号是否存在于集合中的项目中。

【讨论】:

@jafar 您在编辑中的实现使用binary_search 在无序容器中查找数字。要么对向量进行排序,要么使用线性搜索。【参考方案2】:
bool possible(int sum, vector<int> &vec)

    int s = 0;
    for (int i = 0; i<vec.size(); i++)
    
      s += vec.at(i);
    

    if (s==sum)
    return true;
    else
    return false;


这样会更有效率,只需将向量值相加并在最后比较结果即可。在这种情况下,您不需要进行任何排列计算,也不需要在 do...while 循环中使用 for 循环。

【讨论】:

您为索引计数器 i 使用了错误的数据类型。它应该是 size_type 而不是 int。推荐使用迭代器:for ( auto it = vec.begin(); it != vec.end(); ++it ) s += *it; 这也避免了代价高昂的at-calls。【参考方案3】:

我得到了这个工作代码。

bool possible(int sum, vector<int &vec)

    vector<int> previous;
    previous.push_back(0);

    for(auto i = vec.begin(); i != vec.end(); i++)
    
        vector<int> temp(previous);
        for(auto j = temp.begin();  j != temp.end(); j++)
            *j += *i;
        for(auto k = temp.begin(); k != temp.end(); k++)
        
            if(*k <= sum)
                previous.push_back(*k);
        
    
    sort(previous.begin(),previous.end());
    return binary_search(previous.begin(),previous.end(),sum);

谢谢大家。

【讨论】:

以上是关于对向量中的整数序列求和的主要内容,如果未能解决你的问题,请参考以下文章

使用 192/256 位整数对无符号 64 位整数向量的点积求和的最快方法?

对具有 O(1) 复杂度的一系列索引中的值求和 [关闭]

使用 NEON 在 ARM 汇编中对四字向量中的所有元素求和

对多维数组javascript中的所有整数求和

对字符串 C++ 中的所有整数求和

递归地对数组中的整数求和