指出潜在的溢出错误

Point out potential overflow bugs

本文关键字:溢出 错误      更新时间:2023-10-16

这是我解决面试问题的方法。链接

给定一个包含n个从1到n的整数的只读数组。每个整数只出现一次,除了A出现两次,B没有出现。返回A和B。注意:你的算法应该有一个线性的运行复杂度。你能在不使用额外内存的情况下实现它吗?请注意,在输出中,A应该在b之前。N <= 10^5

看起来好像某个地方有溢出问题。你能指出这些地方并提出解决办法吗?

  typedef long long int unit;
vector<int> Solution::repeatedNumber(const vector<int> &A) {
    unit n = A.size();
    unit sum = n*(n+1)/2;
    unit sumsq = n*(n+1)*(2*n+1)/6;
    unit arrsum = std::accumulate(A.begin(), A.end(), 0);

    unit arrsq = 0;
    for(int item : A) {
        arrsq += (unit)item*item;
    }
    unit c1 = arrsum - sum;
    unit c2 = arrsq - sumsq;
    unit a = (c2/c1 + c1);
    a/=2;
    unit b = (c2/c1 - c1);
    b/=2;
    return {a, b};
}

p。这可能是溢出问题,因为同样的解决方案在Python中也有效。

这是一个问题的作者提供的解决方案。有趣的是他是如何通过减法来解决求和中的溢出问题的。

 class Solution {
public:
    vector<int> repeatedNumber(const vector<int> &V) {
       long long sum = 0;
       long long squareSum = 0;
       long long temp;
       for (int i = 0; i < V.size(); i++) {
           temp = V[i];
           sum += temp;
           sum -= (i + 1);
           squareSum += (temp * temp);
           squareSum -= ((long long)(i + 1) * (long long)(i + 1));
       }
       // sum = A - B
       // squareSum = A^2 - B^2 = (A - B)(A + B)
       // squareSum / sum = A + B
       squareSum /= sum;
       // Now we have A + B and A - B. Lets figure out A and B now. 
       int A = (int) ((sum + squareSum) / 2);
       int B = squareSum - A;
       vector<int> ret;
       ret.push_back(A);
       ret.push_back(B);
       return ret;
    }
};

问题是:

unit arrsum = std::accumulate(A.begin(), A.end(), 0);

您需要使用0LL使其将值累加为long long

演示问题的代码:

int main()
{
    vector<int> A;
    for (int i = 0; i < 1000000; ++i)
        A.push_back(1000000);
    long long arrsum = accumulate(A.begin(), A.end(), 0LL);
    cout << arrsum;
    return 0;
}

输出不带LL-727379968和正确的结果。

请注意,您也可以使用accumulate来计算平方和:

unit arrsq = accumulate(A.begin(), A.end(), 0LL, 
                             [](unit x, unit y) { return x + y*y; });

潜在的溢出问题有:

unit sum = n*(n+1)/2;

这里n的最大值是10^5。因此,n*(n+1)将产生10^10,然后根据运算符优先级计算除法。

第二名是

unit sum = n*(n+1)(2*n+1)/6;

这里计算的中间值最高可达10^15。

在计算所有数字的平方和时也会出现整数溢出