查找没有溢出的整数数组的总和
Posted
技术标签:
【中文标题】查找没有溢出的整数数组的总和【英文标题】:Find sum of integer array without overflow 【发布时间】:2013-01-27 07:11:58 【问题描述】:给定一个整数数组(正数和负数),每个整数最多有 K 位(加上符号位),并且已知数组中所有整数的和最多也有 K 位(加上符号位)。设计一种算法,计算数组中整数的总和,所有中间和最多也有 K 位(加上符号位)。 [提示:找出你应该按什么顺序添加正数和负数]。
这是面试材料中的问题,不是家庭作业
我实际上正在考虑创建两个单独的数组,一个用于正数,另一个用于负数,对它们进行排序,然后将两者相加,以便将大多数负数添加到最正数...但这似乎有 O(nlogn) 时间复杂度(排序)和 O(n) 空间复杂度>请帮忙!
【问题讨论】:
只要结果正确,溢出就是问题?如果没有,就求和。 @Ingo 有 ;) 最左边的位 0 反转为 1 @meze 那么,也许最低有效位是 奇/偶 位? 【参考方案1】:首先要注意,即使让即时结果溢出,如果能表示出来,最终结果总是正确的。这是因为在大多数语言中,任何大小的整数类型都类似于循环组,包括 Java(不是在 C 中,整数溢出是未定义的行为,C# 中会抛出溢出异常)。
如果您仍然想要防止溢出,以下是在原地和线性时间内执行它的方法:
将数组原地拆分为负条目(以任何顺序)和正条目(以任何顺序)。零可以在任何地方结束。换句话说,在枢轴为零的情况下执行一个快速排序步骤。
让ni
指向数组的开头(负条目所在的位置)。
pi
指向数组的末尾。
让sum
为零。
而pi >= ni
sum
是负数
将arr[pi]
添加到sum
。
如果arr[pi]
为负数(正加数已用完)且sum
为正数(发生溢出),则结果溢出。
递减pi
其他
将arr[ni]
添加到sum
。
如果arr[ni]
为正,sum
为负,则结果溢出。
递增ni
。
最后,检查sum
是否有超过K
位。如果是,则声明结果溢出。
【讨论】:
你能给个代码吗,我的意思是你怎么看它是否有超过k位?。【参考方案2】:主要思想是使用两个索引迭代数组:正元素和负元素。当总和为负时,我们将搜索下一个正元素(使用相应的迭代器)添加到总和中,否则 - 为负数。
这段代码应该可以工作:
public final class ArrayAdder
@NotNull
private final int[] array;
private int sum;
public ArrayAdder(@NotNull int[] array)
this.array = array;
public int sum()
sum = 0;
final IntPredicate positive = v -> v > 0;
final Index positiveIndex = new Index(positive);
final Index negativeIndex = new Index(positive.negate());
while (positiveIndex.index < array.length || negativeIndex.index < array.length)
sum += sum < 0 ? sum(positiveIndex, negativeIndex) : sum(negativeIndex, positiveIndex);
return sum;
private int sum(@NotNull Index mainIndex, @NotNull Index secondaryIndex)
int localSum = 0;
// searching for the next suitable element
while (mainIndex.index < array.length && secondaryIndex.sign.test(array[mainIndex.index]))
mainIndex.index++;
if (mainIndex.index < array.length)
localSum += array[mainIndex.index++];
else
// add the remaining elements
for (; secondaryIndex.index < array.length; secondaryIndex.index++)
if (secondaryIndex.sign.test(array[secondaryIndex.index]))
localSum += array[secondaryIndex.index];
return localSum;
private static final class Index
@NotNull
private final IntPredicate sign;
private int index;
public Index(@NotNull IntPredicate sign)
this.sign = sign;
【讨论】:
【参考方案3】:选项 1:
就地对数组进行排序并迭代其中的一半。在每一步中,将i
th 元素与size-i-1
th 元素相加。
如果有几个大数字但有很多小负数(反之亦然),则不起作用。
选项 2(改进):
就地排序。
保留两个索引 - 一个在开头,一个在结尾。当他们相遇时退出一个循环。如果到目前为止的结果是负数,则在每一步中添加第二个索引处的值并推进它。如果结果是肯定的,则在第一个索引处添加值并推进它。
【讨论】:
#2 仍然是n log n
。我可以做得更好。
我可以在O(n)
时间内对它们进行排序,但如果 K 很大,则会以大量空间为代价...... :)
我可以做到O(n)
就地时间以上是关于查找没有溢出的整数数组的总和的主要内容,如果未能解决你的问题,请参考以下文章