查找没有溢出的整数数组的总和

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: 就地对数组进行排序并迭代其中的一半。在每一步中,将ith 元素与size-i-1th 元素相加。

如果有几个大数字但有很多小负数(反之亦然),则不起作用。

选项 2(改进):

就地排序。

保留两个索引 - 一个在开头,一个在结尾。当他们相遇时退出一个循环。如果到目前为止的结果是负数,则在每一步中添加第二个索引处的值并推进它。如果结果是肯定的,则在第一个索引处添加值并推进它。

【讨论】:

#2 仍然是n log n。我可以做得更好。 我可以在O(n) 时间内对它们进行排序,但如果 K 很大,则会以大量空间为代价...... :) 我可以做到O(n)就地时间

以上是关于查找没有溢出的整数数组的总和的主要内容,如果未能解决你的问题,请参考以下文章

大数组的堆栈溢出但没有同样大的向量?

VBA 中涉及两个整数和一个长整数的溢出错误

什么是堆栈溢出?

python不是用来处理整数溢出的吗?

使用 Intel Intrinsics 快速查找整数数组的总和

有人可以指出代码“满足给定总和条件的子序列数”的错误,这会导致堆栈溢出错误