2011-02-02 7 views
11

Pregunta De la Entrevista:Hacer un seguimiento de la mediana de una expansión de gama

Editado A continuación Se le da una matriz. Usted hace 2 montones de él, un minheap y el otro montón máximo. Ahora encuentre la mediana de la matriz usando estos 2 montones proporcionados en el tiempo O (nlog n).

Pregunta corregida Los números se generan aleatoriamente y se almacenan en una matriz (en expansión). ¿Cómo harías un seguimiento de la mediana?

Solución Este problema se puede resolver usando 2 pilas y siempre se puede acceder a la mediana en O (1) vez.

+0

Lo que se ha adivinado? – Gumbo

+3

Supongo que la verdadera pregunta es poder determinar la mediana rápidamente incluso después de muchas inserciones y de alguna manera se perdió en la traducción. Francamente, esto parece una pregunta de tarea disfrazada como una pregunta de entrevista. –

+1

@Moron: No estoy de acuerdo con la evaluación de la tarea. Es muy fácil simplemente copiar la declaración de la tarea y no introducir problemas de "pérdida en la traducción". Esto huele más como una pregunta de entrevista que se perdió en la traducción. – jason

Respuesta

3

Saltar desde un montón es una operación O (log N), por lo que puede lograr O (N log N) sacando la mitad de los elementos de uno de los montones y tomando el último valor reventado (tendría que manejar cajas de borde). Sin embargo, esto no aprovecha el otro montón.

Puede lograr O (N) con el selection algorithm, pero el factor constante es muy alto. La sugerencia anterior es probablemente mejor si ya tiene un montón.

+0

sí ... la pregunta era O (nlog n) en sí ... la publicó incorrectamente. – EFreak

+0

@EFreak Pensé que sí, respuesta actualizada. @Downvoter Explique por favor – marcog

+0

La única razón por la que puedo pensar en usar dos montones es para que el borde de N sea par, donde la mediana se define como el promedio de los dos valores medios que obtendría si eliminara N/2 de ambos montones. Sin embargo, parece exagerado para ese propósito. –

12

Así es como usa ambos montones. Tenga en cuenta que asumo que no conoce la cantidad de elementos, y esta es la razón por la que debemos abrir hasta que saquemos algo del montón mínimo que sea mayor o igual que lo que sacamos del montón máximo. Tenga en cuenta que devolvemos el promedio porque en el caso de un conjunto como {1, 2, 3, 4}, la mediana es en realidad 2.5 (el promedio de los dos valores "medios"). Supongo que double es el tipo de valor, pero obviamente puede ser cualquier cosa. Aquí:

double min = minheap.pop(); 
double max = maxheap.pop(); 
while(min < max) { 
    min = minheap.pop(); 
    max = maxheap.pop(); 
} 

return (min + max)/2; 

Desde hace estallar es O(log n) y tenemos que hacer estallar O(n/2) valores, esto es O(n log n).

+1

@marcog: ¿Te molestaste en pensarlo? Considere, por ejemplo, '{1, 2, 3}'. Pop da 'min' como' 1' y 'max' como' 3'. Pop de nuevo da 'min' como' 2' y 'max' como' 2'. La condición 'min jason

+0

@Jason Considere 1, 2, 2. Pop da min 1 max 2. Pop vuelve a dar min 2 max 1. Luego devuelve 1.5 cuando la respuesta debería ser 2. (EDIT: Estaba equivocado, el segundo pop da min 2 max 2.) – marcog

+0

@ Jason Fallé, lo siento, me acabo de dar cuenta de mi error. Invertir el voto. Disculpas – marcog

4

Una implementación de trabajo en java, usando 2 montones, O (n log n). En cualquier momento, mantengo los dos montones equilibrados en tamaño (es decir, difieren a lo sumo en 1, si ingresamos n elementos tales que n% 2 == 1). Obtener la mediana es O (1). Agregar un nuevo elemento es O (log n).

public class MedianOfStream { 

    private int count; 
    private PriorityQueue<Integer> highs, lows; 

    public MedianOfStream() { 
     highs = new PriorityQueue<Integer>(11, new Comparator<Integer>() { 
      @Override 
      public int compare(Integer arg0, Integer arg1) { 
       return arg0.compareTo(arg1); 
      } 
     }); 
     lows = new PriorityQueue<Integer>(11, new Comparator<Integer>() { 
      @Override 
      public int compare(Integer arg0, Integer arg1) { 
       return arg1.compareTo(arg0); 
      } 
     }); 
    } 

    private int getMedian() { 
     if (count == 0) 
      return 0; 
     if (lows.size() == highs.size()) { 
      return (lows.peek() + highs.peek())/2; 
     } else if (lows.size() < highs.size()) { 
      return highs.peek(); 
     } 
     return lows.peek(); 
    } 

    private void swap(){ 
     int h = highs.poll(); 
     int l = lows.poll(); 
     highs.add(l); 
     lows.add(h); 
    } 

    public int updateMedian(int n) { 
     count++; 

     if (count == 1) 
      lows.add(n); 

     else if (count==2) { 
      highs.add(n); 
      if(highs.peek()<lows.peek()) { 
       swap(); // O(log n) 
      } 
     } 

     else { 
      if (n > highs.peek()) { 
       lows.add(highs.poll()); // O(log n) 
       highs.add(n); // O(log n) 
      } else { 
       highs.add(lows.poll()); // O(log n) 
       lows.add(n); // O(log n) 
      } 
      if(highs.peek()<lows.peek()) { 
       swap(); // O(log n) 
      } 
     } 

     // if we added an even # of items, 
     // the heaps must be exactly the same size, 
     // otherwise we tolerate a 1-off difference 

     if (Math.abs(lows.size() - highs.size()) > (count % 2)) { 
      if (lows.size() < highs.size()) { 
       lows.add(highs.poll()); // O(log n) 
      } else { 
       highs.add(lows.poll()); // O(log n) 
      } 
     } 

     return getMedian(); // O(1) 
    } 
} 
-1

solución de JavaScript utilizando dos montones:

function addNewNumber(minHeap, maxHeap, randomNumber) { 
    if (maxHeap.size() === minHeap.size()) { 
    if (minHeap.peek() && randomNumber > minHeap.peek()) { 
     maxHeap.insert(minHeap.remove()); 
     minHeap.insert(randomNumber); 
    } else { 
     maxHeap.insert(randomNumber); 
    } 
    } else { 
    if (randomNumber < maxHeap.peek()) { 
     minHeap.insert(maxHeap.remove()); 
     maxHeap.insert(randomNumber); 
    } else { 
     minHeap.insert(randomNumber); 
    } 
    } 
} 

function getMedian(minHeap, maxHeap) { 
    if (!maxHeap.size()) { 
    return 0; 
    } 
    if (minHeap.size() === maxHeap.size()) { 
    return (minHeap.peek() + maxHeap.peek())/2; 
    } else { 
    return maxHeap.peek(); 
    } 
} 
Cuestiones relacionadas