Java 查找不带溢出的整数数组的和
给定一个整数数组(正整数和负整数),每个整数最多有K位(加上符号位),并且已知数组中所有整数的总和最多也有K位(加上符号位)。设计一种算法,计算数组中整数的和,所有中间和最多也有K位(加上符号位)。[提示:查找应按什么顺序添加正数和负数] 这是来自面试材料的问题,不是家庭作业 我实际上在考虑创建两个单独的数组,一个用于正数组,另一个用于负数组,对它们进行排序,然后将两者相加,以便将最负的数组添加到最正的数组中。。。但这似乎有O(nlogn)时间复杂度(要排序)和O(n)空间复杂度>请帮助 选项1: 在适当的位置对数组进行排序,并对其中的一半进行迭代。在每个步骤中,添加Java 查找不带溢出的整数数组的和,java,algorithm,Java,Algorithm,给定一个整数数组(正整数和负整数),每个整数最多有K位(加上符号位),并且已知数组中所有整数的总和最多也有K位(加上符号位)。设计一种算法,计算数组中整数的和,所有中间和最多也有K位(加上符号位)。[提示:查找应按什么顺序添加正数和负数] 这是来自面试材料的问题,不是家庭作业 我实际上在考虑创建两个单独的数组,一个用于正数组,另一个用于负数组,对它们进行排序,然后将两者相加,以便将最负的数组添加到最正的数组中。。。但这似乎有O(nlogn)时间复杂度(要排序)和O(n)空间复杂度>请帮助 选项1
i
th元素和size-i-1
th元素
如果有几个大数字,但有许多小负数(反之亦然),则不起作用
备选案文2(改进):
分类到位
保留两个索引—一个在开始处,一个在结束处。当它们相遇时退出循环。在每个步骤中,如果到目前为止结果为负,则在第二个索引处添加值并将其前进。如果结果为正,则在第一个索引处添加值并使其前进。首先请注意,即使立即结果溢出,如果可以表示,最终结果也始终是正确的。这是因为在包括Java在内的大多数语言中,任何大小的整数类型的行为都类似于加法下的循环组(而不是在C中,整数溢出是未定义的行为,而C#可以引发溢出异常) 如果您仍然希望防止溢出,下面介绍如何在适当的位置和线性时间内执行溢出:
- 将数组就地拆分为负项(按任意顺序)和正项(按任意顺序)。零可以在任何地方结束。换句话说,在枢轴为零的情况下执行一个快速排序步骤
- 让
指向数组的开头(负项所在的位置)ni
- 让
指向数组的末尾pi
- 让
和
为零
- 而
pi>=ni
- 如果
为负sum
- 将
添加到arr[pi]
中sum
- 如果
为负(正加数已用完)且arr[pi]
为正(发生溢出),则结果溢出sum
- 减量
pi
- 将
- 否则
- 将
添加到arr[ni]
中sum
- 如果
为正,而arr[ni]
为负,则结果溢出sum
- 增量
ni
- 将
- 如果
- 最后,检查
是否超过sum
位。如果是,则声明结果溢出K
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;
}
}
}
public final类数组adder{
@NotNull
私有final int[]数组;
私人整数和;
public arrayDDER(@NotNull int[]数组){
this.array=数组;
}
公共整数和(){
总和=0;
最终INT谓词正=v->v>0;
最终指数正指数=新指数(正);
最终索引negativeIndex=新索引(正.否定());
while(正索引
只要结果正确,溢出是否是一个问题?如果没有,就求和。@Ingo有;)最左边的位0被反转为1@meze那么,最低有效位可能是奇偶位?#2仍然是n log n
。我可以做得更好。我可以在O(n)
时间内对它们进行排序,但如果K较大,则会以大量空间为代价…)我可以做O(n)
time-in-place你能给我一个代码吗,我的意思是你怎么看它是否有超过k位?。