Determinar si una matriz tiene un elemento de mayoría k

Supongamos que, dado un multiconjunto A de n elementos (no ordenado), queremos un algoritmo de tiempo O(n) para determinar si A contiene un elemento mayoritario, es decir, un elemento que aparece más de n/2 veces en A. Es fácil de resolver esto en tiempo O(n) usando el algoritmo de selección de tiempo lineal encontrando la mediana (llámela x), luego contando cuántas veces x ocurre en A y devolviéndola como la mayoría si el conteo excede n/2 (de lo contrario, la respuesta es "no hay mayoría"). Ahora considere la siguiente generalización del problema: dado A y un entero k < n, queremos un algoritmo que determine si A contiene un valor que aparece más de n/k veces en él (si existen muchos de estos valores, entonces es suficiente para encontrar uno de ellos). Diseñe un algoritmo para hacer esto y analice su complejidad en función de n y k. Su calificación en esta pregunta dependerá de qué tan rápido sea su algoritmo (por supuesto, también tiene que ser correcto). Se otorga un crédito parcial de 10 puntos por un algoritmo de tiempo O(kn), el crédito total es por un algoritmo de tiempo O(n log k).

ahora se me ocurrieron 2 soluciones para el problema, pero ninguna satisface completamente el requisito de O (n log k). Inmediatamente vi que podía ordenar la matriz usando un algoritmo O (n log n) y luego revisar y ver si algún elemento se repite más de n/k veces linealmente, pero eso es O (n log n) no O (n log k)

También encontré y entendí un poco un método O (nk) hecho al hacer una matriz del mismo tipo de datos que la entrada y un int que es k largo. luego colocando cada elemento en un elemento vacío incrementando su contador o si coincide con un elemento allí incrementando su contador hasta que alcancemos el elemento único k + 1 en cuyo punto disminuye todos los contadores en 1 hasta que uno llega a 0 en cuyo punto es se considera vacío y el nuevo elemento se puede colocar en él. y así sucesivamente hasta el final de la matriz de entrada. luego verificamos todos los elementos que quedan después de que hayamos terminado para ver si ocurren más de n/k veces. pero dado que esto implica comparar los n elementos originales con todos los k de los nuevos elementos del arreglo, es O(nk). ¿algún consejo sobre cómo resolver este problema en O(n log k)? Creo que el algoritmo O(nk) está en la línea de cómo él quiere que pensemos, pero no estoy seguro de adónde ir desde aquí.

preguntado el 24 de agosto de 12 a las 22:08

gracias avi cohen, tu idea me ayudó en el camino correcto. Tuve algunos problemas para descubrir cómo proceder después de dividirlo en las subsecciones sin hacer comparaciones nk, pero finalmente lo descubrí.

3 Respuestas

El método que describiste solo necesita usarse recursivamente.

Recordando eso select mueve los elementos que son menores o iguales a la mediana a la izquierda de la mediana.

If A es de tamaño n.

Encuentre la mediana de A. Ahora encuentre la mediana de cada uno de los dos subconjuntos múltiples de longitud n/2 que fueron particionados por la mediana. Encuentre la mediana de cada uno de los cuatro subconjuntos múltiples de longitud n/4 que estaban divididas por las medianeras. Continúe recursivamente hasta que las hojas tengan una longitud n/k. Ahora la altura del árbol recursivo es O(lgk). En cada nivel del árbol recursivo, hay O(n) operaciones. Si existe un valor que se repite al menos n/k tiempos entonces será en uno de estos k con una longitud de n/k sub multiconjuntos. Las últimas operaciones también se hacen en O(n). Entonces obtienes el tiempo de ejecución solicitado de O(nlgk).

Respondido 24 ago 12, 23:08

Algoritmo O(kn)

Me pregunto si quizás el algoritmo O(kn) podría estar más en la línea de:

  1. Encuentre k elementos espaciados regularmente (usando un algoritmo de selección lineal similar a la mediana)
  2. Cuente cuántas coincidencias obtiene para cada uno de estos

Con la idea de que si un elemento aparece n/k veces, debe ser uno de estos.

Algoritmo O (nlogk)

Quizás podría usar el esquema propuesto en su pregunta junto con una estructura de árbol para contener los elementos k. Esto significaría entonces que la búsqueda de una coincidencia solo sería log(k) en lugar de k, para un O(nlogk) general.

Tenga en cuenta que debe usar el árbol tanto para el primer paso (donde está encontrando k candidatos que debemos considerar) como para el segundo paso de calcular los recuentos exactos para cada elemento.

También tenga en cuenta que probablemente desee utilizar un esquema de evaluación perezoso para decrementar los contadores (es decir, marcar subárboles completos que deben decrementarse y propagar los decrementos solo cuando se use esa ruta a continuación).

Algoritmo O(n)

Si encuentra esto en la vida real, consideraría usar un diccionario basado en hash para almacenar el histograma, ya que esto debería brindar una solución rápida.

por ejemplo, en Python podría resolver esto en (en promedio) O (n) tiempo usando

from collections import Counter
A=[4,2,7,4,6]
k=3

element,count = Counter(A).most_common()[0]

if count>=len(A)//k:
    print element
else:
    print "there is no majority"

Respondido 24 ago 12, 23:08

No sé si has visto este, pero te puede servir para darte ideas:

Suponga que sabe que hay un elemento mayoritario en una matriz L.

Una forma de encontrar el elemento es la siguiente:

Def FindMajorityElement(L):

    Count = 0

    Foreach X in L

        If Count == 0
            Y = X

        If X == Y
            Count = Count + 1
        Else
            Count = Count - 1

    Return Y

O(n) tiempo, O(1) espacio

Respondido 24 ago 12, 23:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.