He encontrado la siguiente pregunta de la entrevista aquí.
SortedIterator - Consiste en la lista de listas con valores int ordenados en cada lista. Usted tiene que dar el próximo valor de ordenada cuando la llamada siguiente ().
que poner en práctica los métodos constructor * * next () * hasNext ()
[[1, 4, 5, 8, 9], [3, 4, 4, 6], [0, 2, 8]]
next () -> 0, 1, 2, 3, 4, 4, 4 ...
Escribí una rápida implementación en Java:
package com.app;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class SortedIterator implements Iterator<Integer> {
private final List<Integer> mFlattenedList;
private final Iterator<Integer> mIntegerIterator;
SortedIterator(final List<List<Integer>> lists) {
mFlattenedList = flattenLists(lists);
mIntegerIterator = mFlattenedList.iterator();
}
private List<Integer> flattenLists(final List<List<Integer>> lists) {
final List<Integer> result = new ArrayList<>();
for (List<Integer> list : lists) {
for (int value : list) {
result.add(value);
}
}
Collections.sort(result);
return result;
}
@Override
public boolean hasNext() {
return mIntegerIterator.hasNext();
}
@Override
public Integer next() {
return mIntegerIterator.next();
}
}
Tiempo: O (K * N) para aplanar la lista de entrada de listas + O (N * K) para iterar sobre la lista aplanada = O (N * K)
Espacio: O (N * K) para almacenar la lista aplanada.
N - número de listas.
K - número de elementos en cada lista.
Pero la respuesta desde el enlace dice:
Hay una solución con el tiempo la complejidad O (logN) usando una cola de prioridad. Tal vez un entrevistador esperaba algo así, no sé.
¿Cómo es O (log N)
posible? Si se utiliza una cola de prioridad, cada vez que llamamos hasNext()
, tendremos que comprobar si la cola está vacía ( O(1)
). Entonces llamamos next()
que extrae el elemento min de la cola ( O(log (N*K)
) para cualquier aplicación) de acuerdo con la tabla . Puesto que tenemos que llamar a next()
veces N * K, nos lleva O(N * K * log (N*K)
a iterar sobre todos los elementos.
O (logN) La complejidad de la solución es la complejidad por elemento , no la complejidad para iterar sobre todos los valores.
La solución es como la siguiente:
En primer lugar definir una nueva clase llamada
ListValue
que almacena un valor, así como el índice de la lista de vino. Estos deben ser comparable a otrosListValue
objetos utilizando el valor.Constructor: inicializar una
PriorityQueue<ListValue>
llamadapq
y colocar el primer elemento de cada una de las listas de N enpq
.next (): Pop the
ListValue
en la parte delanterapq
. El valor en el interior es el valor a devolver, pero en primer lugar, se mueve al siguiente elemento de esaListValue
lista de 's enpq
. La complejidad es O (log N), ya que eliminamos un elemento y añadimos un elemento apq
, que contiene en la mayoría de N elementos.
Tenga en cuenta que la solución no conserva todos los valores de N * K en la cola de prioridad a la vez, sólo el único valor "al lado" de cada una de las listas N. Por lo tanto, la cola de prioridad tiene (como máximo) N elementos en todo momento, por lo que sus operaciones son todos O (log N).
Para entender por qué esto funciona, recordemos que cada lista ya está ordenado, por lo que el valor mínimo no utilizada debe aparecer en el "frente" de alguna lista (sin incluir los valores ya consumidos). Luego, nota que la cola de prioridad contiene precisamente el elemento "front" de cada lista - obligamos a que esto suceda en next()
cuando añadimos un elemento a pq
partir de la misma lista que el elemento hemos eliminado. Por lo tanto, en todo momento pq
contendrá el valor mínimo no utilizada (hasta que todos los valores son agotado).