Java 查找不带溢出的整数数组的和

Java 查找不带溢出的整数数组的和,java,algorithm,Java,Algorithm,给定一个整数数组(正整数和负整数),每个整数最多有K位(加上符号位),并且已知数组中所有整数的总和最多也有K位(加上符号位)。设计一种算法,计算数组中整数的和,所有中间和最多也有K位(加上符号位)。[提示:查找应按什么顺序添加正数和负数] 这是来自面试材料的问题,不是家庭作业 我实际上在考虑创建两个单独的数组,一个用于正数组,另一个用于负数组,对它们进行排序,然后将两者相加,以便将最负的数组添加到最正的数组中。。。但这似乎有O(nlogn)时间复杂度(要排序)和O(n)空间复杂度>请帮助 选项1

给定一个整数数组(正整数和负整数),每个整数最多有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位?。