我为Hackerrank挑战编写了一个解决方案,其中我将大量数字汇总到一个总变量中。当我使用整数时,我注意到我在一个测试用例中溢出,但所有其他测试用例都输出了正确的答案。当我将total
变量切换为长以避免溢出时,我开始溢出两个测试用例(与之前相同,另一个)。将total
,numToSell
,和 lastMax
更改为long后,程序会计算出正确的答案。
会导致这种情况发生的原因是什么?我希望将变量从int移到long应该永远不会导致溢出。
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int T = in.nextInt();
while(T-->0)
{
int N = in.nextInt();
int[] price = new int[N];
for(int i = 0; i < N; ++i)
{
price[i] = in.nextInt();
}
int lastMax = price[N-1]; //works when this and numToSell are longs
int numToSell = 0;
long total = 0; //if this is also an int, only overflows in one case in my samples
for(int i = N - 2; i >= 0; --i)
{
if(price[i] <= lastMax)
{
++numToSell;
total -= price[i];
}
else
{
total += numToSell*lastMax;
lastMax = price[i];
numToSell = 0;
}
}
total += numToSell*lastMax;
System.out.println(total);
}
}
}
在受影响的测试用例中,N为39,384,数组中的每个数字介于1到100000之间。
答案 0 :(得分:2)
是的,因为这里
total += numToSell*lastMax;
如果numToSell
和lastMax
int
是整数乘法。 int * int = int。然后,您将int
添加到long
。当numToSell
(或lastMax
)很长时,特定的乘法指令将按预期工作。我注意到你在两个地方进行数学运算。
答案 1 :(得分:0)
我猜你是否刚刚将total
更改为long并将numToSell
和lastMax
更改为int,那么numToSell*lastMax
仍然会溢出并给出错误的结果已添加到total
答案 2 :(得分:0)
如果total,numToSell和lastMax都是整数,那么在某些情况下,事情可以取消,并且会意外地给出正确的答案。如果总数很长但另一个是整数,则不一定会发生这种情况。
这是一个遍历循环的例子。
prices = {2000001,2000000,2000000,2000000};
lastMax = 2000000;
numToSell = 0;
total = 0;
loop:
iteration 1:
numToSell = 1;
total = -2000000
iteration 2:
numToSell = 2;
total = -4000000 // oh no, we underflowed if we are int, but not long!
iteration 3:
total = -4000000 + (2 * 2000000) // let's take a deeper look at this below
numToSell = 0;
lastMax = 20000001
total += 0;
让我们来看看这一行:总计= -4000000 +(2 * 2000000)
如果total,numToSell和lastMax都是整数,那么total = 0.这是因为总下溢和(2 * 20000000)将以完全相同的方式溢出。所以两人取消了。
如果它们都是长的,那么没有任何溢出,所以总数= -40000000 +(2 * 2000000)= 0.
如果总数很长,那么当设置为-4000000时总数不会下溢。但是,(2 * 2000000)是一个整数,它将溢出并成为负数。所以总数不会为零!
这是一个所有整数都有效的情况,所有长篇都有效,但混合失败。