面试中心挑战

时间:2012-06-13 02:18:21

标签: algorithm median

问题 M个数的中位数定义为 1)如果M按顺序排序后是奇数中间数 2)如果M是中间2个数的平均数(再次排序后) 您首先有一个空号码列表。然后,您可以在列表中添加或删除一些数字。对于每个添加或删除操作,输出列表中的数字中位数。

示例:对于一组m = 5的数字,{9,2,8,4,1},中位数是排序集{1,2,4,8,9}中的第三个数字,即4。对于m = 4,{5,2,10,4}的集合,中位数是有序集{2,4,5,10}中第二和第三个元素的平均值,即(4 + 5)/ 2 = 4.5

我的方法 我认为问题可以通过这种方式解决.. 想法是使用先前的中值和指针来查找新的中值而不是在每次添加或删除操作时重新计算。

1)使用多重集合,它始终按顺序保留元素并允许重复。换句话说,以某种方式维护排序列表。

2)如果操作是添加

2.1) Insert this element into set and then calculate the median

2.2) if the size of set is 1 then first element will be the median

2.3) if the size of set is even, then

           if new element is larger then prev median, new median will be avg of prev median

               and the next element in set.

           else new median will be avg of prev median and previous of prev element in the set.

2.4) if the size is odd, then

          if new element is larger then prev median

                 if also less then 2nd element of prev median ( 2nd element used to calculate avg

                    of prev median) then this new element to be added will be new median

                 else median will be 2nd element use to calculate the avg during last iteration prev

                    median.

          else

                 new median will be previous of prev median element in the set

3)如果删除操作

3.1) First calculate the new median

3.2) If the size of set is 0 can't remove

3.3) If the size is 1 if the first element is the element to be removed, remove it else can't remove.

3.4) If the size of set is even, then

           if the element to be deleted is greater than or equal to 2nd element of prev median, then

               1st element of prev median will be new median

          else 2nd element of prev median will be the new median

3.5) If the size of set is odd, then

           if the element to be deleted is the prev median then find the avg of its prev and  next element.

           else if the element to be deleted is greater then prev median, new median will be avg of prev median and previous to prev median

           else median will be avg of prev median and next element to prev median.

3.6) Remove the element. 

这是工作代码...... http://justprogrammng.blogspot.com/2012/06/interviewstreet-median-challenge.html。您对此方法有何看法?

6 个答案:

答案 0 :(得分:4)

您的方法似乎可行,但从描述和代码中,您可以看出涉及很多案例工作。我不想成为那个必须调试的人!因此,让我给你一个替代解决方案,它应该涉及更少的案例,因此更容易做对。

保留两个多重集(此算法也适用于两个优先级队列,因为我们只会查看每个队列的极值)。第一个minset将保留最小的n / 2个数字,第二个maxset将保存最后的n / 2个数字。

每当你添加一个数字时:

  • 如果大于max(minset),请将其添加到maxset
  • 否则,请将其添加到minset

请注意,这并不能保证n / 2条件。因此,我们应该添加一个额外的“修复”步骤:

  • 如果maxset.size() > minset.size(),请移除maxset中的最小元素并将其插入minset
  • 如果minset.size() > minset.size() + 1,请移除minset中最大的元素并将其插入maxset

完成此操作后,我们只需要获得中位数。这对我们的数据结构来说应该很容易:取决于当前n是偶数还是奇数,它可以是max(minset),也可以是max(minset)min(maxset)之间的平均值。

对于删除操作,只需尝试将其从任何一组中删除,然后再进行修复。

答案 1 :(得分:1)

您的代码的主要问题是每个新项目与运行中位数的比较,这可能是计算出的平均值。相反,您应该将新项目与前一个中间值(代码中的*prev)进行比较。在接收到1和5的序列之后,你的中值将是3.如果下一个值是2或4,它应该成为新的中值,但是因为你的代码遵循不同的路径,每个结果是错误的。

总体而言,仅仅跟踪中间位置而不是正在运行的中位数会更简单。相反,计算每个添加/删除操作结束时的中位数:

if size == 0
    median = NaN
else if size is odd
    median = *prev
else
    median = (*prev + *(prev-1)) / 2

答案 2 :(得分:1)

我认为您可以尝试验证两种情况:

1) negative number
4
a -1
a 0
a 0
r 0

2) two big integer whose sum will exceed max int

答案 3 :(得分:0)

如果您的列表已排序,那么您可以使用类似于以下伪代码的方法计算恒定时间的中位数

if list.length % 2 == 0 
   median = (list[list.length/2 - 1] + list[list.length/2]) / 2 
else
   median = list[list.length/2]

因此,只需在每次插入/删除时维护一个排序列表。您可以在O(n)时间内逐步执行这些操作,直到您处于<添加的元素和> =添加的元素。如果从列表中间开始然后确定您的元素是否小于或大于中间元素,则实际上可以在O(log n)时间内执行这些插入/移除操作。拿出半个清单,然后从中间开始重复。

你的问题没有说明性能要求是什么,但据我所知,整个事情并不总是在不断的时间内发生。此实现具有以下性能

Insert    O(log n)
Remove    O(log n)
Median    O(1)

答案 4 :(得分:0)

此代码解决了interviewStreet的中位数挑战。

# this code solves the median challenge on interviewStreet.
# logic is simple. insert the numbers into a sorted sequence in place.
# use bisection to find the insert index(O(logn)). keep a count of no. of elements in
# the list and print the median using it(O(1)).
!/bin/python
from bisect import bisect_left
List = [] 
nnode = 0 

def printMed():
if nnode>0:
    if nnode%2 == 0 :
    if (0.5*(List[nnode/2]+List[(nnode/2)-1])).is_integer():
        print int(0.5*(List[nnode/2]+List[(nnode/2)-1]))
    else:
        print 0.5*(List[nnode/2]+List[(nnode/2)-1])
    else:
    print List[nnode/2]
else:
    print "Wrong!"

def rem(val):
global nnode
try:
        List.remove(val)
except:
    print "Wrong!"
else:
    nnode = nnode-1
    printMed()

if __name__ == "__main__":
    n = int(raw_input())
for i in range(0,n):
    l = raw_input().split()
    if(l[0] == 'r'):
        rem(int(l[1]))
    else:
    index = bisect_left(List , int(l[1])) ;
    List.insert(index ,int(l[1]))
    nnode = nnode+1 
    printMed() 

答案 5 :(得分:0)

这是使用collections.sort(list)

在java中进行中值挑战的解决方案
import java.util.*;
public class SolutionMedian{
    ArrayList<Integer> sortedList = new ArrayList<Integer>();

    public static void main(String args[]){

        SolutionMedian m = new SolutionMedian();

        Scanner in = new Scanner(System.in);
        int n = in.nextInt();

        char[] op = new char[n];
        int[] val = new int[n];
        for(int i=0; i<n; i++){
            op[i] = in.next().charAt(0);
            val[i] = in.nextInt();
        }

        for(int i=0; i<n; i++)
            if(op[i] == 'a') 
                m.add(val[i]);
            else 
                m.remove(val[i]);
    }

void add(int val){
        sortedList.add(val);
        getMedian();
    }

    void remove(int val){
        int index = sortedList.indexOf(val);
        if(index>=0){
            sortedList.remove(index);
            getMedian();
        }else{ 
            System.out.println("Wrong!");
        }
    }

    void getMedian(){
        Collections.sort(sortedList);
        int size = sortedList.size();
        switch(size){
            case 0: 
                System.out.println("Wrong!");
                break;
            case 1: 
                System.out.println(sortedList.get(0));
                break;
            default: 
                if(size%2 == 0) {//even size
                    int halfIndex = size/2;
                    long sum = sortedList.get(halfIndex)
                              + sortedList.get(halfIndex-1);
                    if(1==(sum&1)) 
                        System.out.println((sum/2)+".5");
                    else 
                        System.out.println(sum/2);
                }else{//odd size
                    System.out.println(sortedList.get((size-1)/2));
                }
        }
    }
}