大数数组的平衡索引,如何防止溢出?

Posted

技术标签:

【中文标题】大数数组的平衡索引,如何防止溢出?【英文标题】:Equilibrium index of an array of large numbers, how to prevent overflow? 【发布时间】:2015-02-04 05:33:02 【问题描述】:

问题陈述: 数组的平衡索引是数组中的索引,使得较低索引处的元素之和等于较高索引处的元素之和。 例如,在 -7, 1, 5, 2, -4, 3, 0 中,3 是一个均衡指数,因为: -7 + 1 + 5 = -4 + 3 + 0

编写一个函数,给定一个整数向量,返回其平衡索引(如果有)。假设向量可能很长。

问题: 我发现的所有解决方案(有效)都是基于这样一个事实,即给定所有元素的总和和一个部分的当前运行总和,我们可以通过扣除剩余部分的元素总和来获得。 我不认为解决方案是正确的,因为如果我们提供带有 MAX_INT 元素的大向量,元素总和将导致溢出。如何解决溢出问题? 有关建议解决方案的参考,所有这些都无法解决溢出问题 (我只指 C++ 实现,据我所知,在 Java 中存在解决它的 BigInteger 类) http://blog.codility.com/2011/03/solutions-for-task-equi.html 补充材料:

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

template <typename T>
std::vector<size_t> equilibrium(T first, T last)

    typedef typename std::iterator_traits<T>::value_type value_t;

    value_t left  = 0;
    value_t right = std::accumulate(first, last, value_t(0));
    std::vector<size_t> result;

    for (size_t index = 0; first != last; ++first, ++index)
    
        right -= *first;
        if (left == right)
        
            result.push_back(index);
        
        left += *first;
    
    return result;


template <typename T>
void print(const T& value)

    std::cout << value << "\n";


int main() 

    const int data[] =  -7, 1, 5, 2, -4, 3, 0 ;

    std::vector<size_t> indices(equilibrium(data, data + 7));

    std::for_each(indices.begin(), indices.end(), print<size_t>);

【问题讨论】:

链接到problem statement 【参考方案1】:

简短的回答是,最终它无法完全治愈/解决,除非您限制输入的数量/数量 - 即使使用 Java 的 BigInt(或 C++ 的等价物,如 gmp、NTL 等)也不行.)

问题很简单:任何计算机的内存都是有限的。我们可以表示的数字总会有一些有限的限制。任意精度的整数类型可以增加对数字的限制,远远大于大多数使用的定期工作,但是无论限制可能是什么,总会有非常大的数字可以' t 被表示(至少在不改变为其他表示的情况下——但如果我们要精确到任意数字的单位位置,那么我们在表示庞大数字方面的聪明程度就会受到明显的限制)。

对于链接问题中给出的条件,C 和 C++ 中的long long 类型就足够了。如果我们想通过 C++ 中的解决方案将限制增加到一些荒谬的大小,这非常简单。尽管它们不是 C++ 实现的必需部分,但有许多可用于 C++ 的任意精度整数库。

我想可能有某种方法来计算这个问题的答案,而不涉及实际对数字求和——但至少乍一看,这个想法似乎不太有希望对我来说。问题的陈述是专门关于计算总和的。虽然您当然可以执行各种诡计来使求和看起来像求和一样看起来,但事实是问题的基本陈述涉及求和,这往往表明不涉及求和的解决方案可能好难找。

【讨论】:

我的观点是:是的,由于精度有限,我们无法计算总和,正如你所提到的,但可能存在我们不计算总和的方法???可以尝试使用差异,日志......所以我的问题不是关于无限数字的总和,而是另一种避免使用 sum 的方法 @spin_eight:我在答案中添加了一些关于此的内容。 是的,谢谢你我注意到你的变化。在发布我的问题时,我希望得到比“乍一看可能……”这样的答案更严格的答案。虽然基于 sum 的语句,但问题可能会简化为没有 sum 的问题 @spin_eight:基本上不可能证明不存在这样的方法,所以除非有人设计出一种不涉及对数字求和的方法,否则任何人所能做的最好的事情就是承认他们不存在'不知道这样的事情。【参考方案2】:

是的,这是可能的。请注意,如果data[0] &lt; data[len - 1],则data[1] 应属于“左”部分;同样,如果data[0] &gt; data[len-1]data[len-2] 属于“正确”部分。这一观察结果可以归纳证明以下算法的正确性:

left_weight = 0; right_weight = 0
left_index = 0; right_index = 0

while left_index < right_index
    if left_weight < right_weight
        left_weight += data[left_index++];
    else
        right_weight += data[--right_index]

仍然存在累积,但通过跟踪不平衡和哪一侧更重的布尔指示符很容易处理:

while left_index < right_index
    if heavier_side == right
        weight = data[left_index++]
    else
        weight = data[--right_index]

    if weight < imbalance
        imbalance = imbalance - weight
    else
        heavier_side = !heavier_side
        imbalance = weight - imbalance

至少对于未签名的data,没有溢出的可能性。签名值可能需要进行一些修改。

【讨论】:

第一部分 left_weight += data[left_index++]; - 可能发生溢出;在第二部分中,您如何找到哪一侧更重? 这是通过比较重量和不平衡来决定的。如果重量越大,不平衡就会向另一侧移动,它会变得更重,否则不平衡就会减少。

以上是关于大数数组的平衡索引,如何防止溢出?的主要内容,如果未能解决你的问题,请参考以下文章

大数打印问题

大数求阶乘(防溢出)

大数算法

算法:平衡树求第k大数 Sm 前段时间刚学会了用快速排序来求一个列中的第 k大数,可是她觉得每次 序列被改变

关于大数相乘 溢出的问题

大数乘法取模运算(二进制)