在恒定时间内查找平均值和中位数

时间:2017-03-28 14:45:05

标签: java algorithm data-structures

这是一个常见的面试问题。 你有一串数字进来(比方说超过一百万)。数字介于[0-999]之间。

Implement a class which supports three methods in O(1) 

* insert(int i); 
* getMean(); 
* getMedian(); 

这是我的代码。

public class FindAverage {

  private int[] store;
  private long size;
  private long total;
  private int highestIndex;
  private int lowestIndex;

  public FindAverage() {
    store  = new int[1000];
    size = 0;
    total = 0;
    highestIndex = Integer.MIN_VALUE;
    lowestIndex = Integer.MAX_VALUE;

  }

  public void insert(int item) throws OutOfRangeException {
    if(item < 0 || item > 999){
      throw new OutOfRangeException();
    }
    store[item] ++;
    size ++;
    total += item;
    highestIndex = Integer.max(highestIndex, item);
    lowestIndex = Integer.min(lowestIndex, item);
  }

  public float getMean(){
    return (float)total/size;
  }

  public float getMedian(){

  }
}

我似乎无法想到在O(1)时间内获得中位数的方法。 任何帮助表示赞赏。

3 个答案:

答案 0 :(得分:10)

通过构建store计数器,您已经完成了所有繁重的工作。加上size值,这很容易。

您只需开始迭代store,总结计数,直至达到size的一半。如果size是奇数,那就是你的中值。对于偶数size,您将获取周围的两个值并得到它们的平均值。

性能平均为 O(1000/2),这意味着 O(1),因为它不依赖于n,即性能即使n达到数十亿,也不会改变。

请记住, O(1)并不意味着即时甚至快速。正如Wikipedia所说:

  

如果T(n)的值受一个不依赖于该值的值限制,则算法被认为是恒定时间(也写为 O(1)时间)输入的大小

在你的情况下,该界限是1000。

答案 1 :(得分:3)

您可以阅读的可能值非常有限 - 只有1000.因此您可以考虑实现类似counting sort的内容 - 每次输入数字时,您都会增加该值的计数器。

要在恒定时间内实现中位数,您需要两个数字 - 中位数指数(即中位数值)和您已读取的数值以及中位数左侧(或右侧) 。我将在此停止,希望您能够找到如何继续自己。

EDIT(正如评论中所指出的):您已经拥有了带有排序元素(stored)的数组,并且您知道中位数左侧的元素数量(size/2)。您只需要将逻辑粘合在一起。我想指出,如果使用线性附加内存,则不需要在每个插入上遍历整个数组。

答案 2 :(得分:1)

对于一般情况,其中元素范围不受限制,此类数据结构不存在基于任何基于比较的算法,因为它将允许{{1}排序。

证明:假设存在此类DS,请将其设为O(n)
D为输入数组进行排序。 (假设A即使是为了简单起见,也可以通过添加垃圾元素并稍后将其丢弃来轻松放松。

A.size()

声明1:此算法在sort(A): ds = new D() for each x in A: ds.add(x) m1 = min(A) - 1 m2 = max(A) + 1 for (i=0; i < A.size(); i++): ds.add(m1) # at this point, ds.median() is smallest element in A for (i = 0; i < A.size(); i++): yield ds.median() # Each two insertions advances median by 1 ds.add(m2) ds.add(m2) 中运行。
证明:由于我们有add()和median()的常数运算,每次迭代都是O(n),迭代次数是线性的 - 复杂性是线性的。

权利要求2:对输出进行排序(A)。
证明(指南):插入n次O(1)后,中位数是m1中的最小元素。在将中位数推进一个项目之后的每两次插入,并且由于预先排序,所以对总输出进行排序。

由于上述算法在A中排序,而在比较模型下不可能,因此不存在此类DS。

QED。