Análisis de algoritmo de modo

  Declaración de derechos de autor: Este artículo es original de Colin Cai, bienvenido a volver a publicar. Para volver a publicar, debe indicar la dirección URL original 

  http://www.cnblogs.com/Colin-Cai/p/12664044.html 

  Autor: ventanas 

  QQ / carta micro: 6679072 

  E-mail: [email protected]

  El llamado modo proviene de tal problema: una matriz de longitud len, donde un número aparece más que len / 2, cómo encontrar este número.

  

  Basado en la clasificación

 

  Ordenar es el primer sentimiento, es decir, ordenar la matriz y recorrerla nuevamente para obtener el resultado.

  Básicamente escrito en lenguaje C es el siguiente:

int find ( int a, int len) 
{ 
    sort (a, len); 
    vuelta transversal (a, len); 
}

  La ordenación tiene algoritmos de complejidad de tiempo O (nlogn) , como la ordenación rápida, la ordenación por fusión y la ordenación de almacenamiento dinámico, y atravesar la matriz ordenada para obtener el resultado es la complejidad lineal de tiempo, que es O (n) . Entonces, la complejidad temporal de todo el algoritmo es O (nlogn) .

 

  Encuentra un mejor algoritmo

 

  El algoritmo anterior es demasiado simple, y muchas veces las cosas que podemos sacar de nuestro primer sentido no son necesariamente confiables.

  ¿Podemos encontrar un algoritmo lineal de nivel de tiempo, es decir, Θ (n) algoritmo de nivel de tiempo? Θ es el mismo símbolo para los límites superior e inferior. De hecho, es fácil demostrar que no existe un algoritmo más bajo que el nivel de tiempo lineal, es decir, el tiempo o (n) . El pequeño o es diferente del gran O, lo que significa un infinito de orden bajo. La prueba es aproximadamente la siguiente:

  Si un algoritmo puede resolver el problema anterior con o (n) complejidad de tiempo. Debido a que es un infinito de orden inferior a n, entonces debe haber una matriz de longitud N. Después de completar este algoritmo, los elementos detectados en la matriz son menores que N / 2. Suponiendo que el resultado de la operación del algoritmo es a, reemplazamos todos los elementos de esta matriz que no se detectaron durante la operación de la matriz con el mismo número b que no es el resultado a del algoritmo. Luego, el algoritmo calcula la nueva matriz, porque el número que no se ha detectado no afectará el resultado del algoritmo, el resultado es naturalmente a, pero de hecho, la cantidad de ocurrencias de la matriz más de N / 2 veces es b. Esto lleva a contradicciones, por lo que el algoritmo de tiempo o (n) para este problema no existe.

  

  Ahora podemos comenzar a pensar en algo más profundo.

  Primero encontraremos que si hay dos números diferentes en una matriz, elimine los dos números de la matriz para obtener una nueva matriz, entonces la nueva matriz todavía tiene el mismo modo que la matriz anterior. Este es fácil de probar:

  Supongamos que la matriz es a, la longitud es len, el modo es x y el número de ocurrencias es t. Por supuesto, t> len / 2 está satisfecho. Supongamos que hay dos números y y z, y ≠ z. Elimine estos dos números, la longitud restante de la matriz es len-2. Si estos dos números no son iguales al modo x, es decir, x ≠ y y x ≠ z, entonces el número de veces que aparece x en la nueva matriz sigue siendo t, t> len / 2> (len-2) / 2, Entonces t sigue siendo el modo en la nueva matriz. Y si x existe en estos dos números, entonces, naturalmente, solo hay una x, entonces el número de ocurrencias de x en la matriz restante es t-1, t-1> len / 2-1 = (len-2) / 2, entonces x sigue siendo el modo de la nueva matriz.

  

  Con las ideas anteriores, pensaremos en cómo encontrar los diferentes números de este par.

  Podemos registrar el número num y el número de veces que se repite, recorrer la matriz una vez, de acuerdo con el siguiente diagrama de flujo.

 

 

  num / times siempre ha registrado el número y sus repeticiones. Los tiempos más 1 y menos 1 están determinados por si el nuevo número de la matriz es el mismo que num. Para diferentes números, elimine estos dos, y el modo de la matriz restante no cambiará. 

  El punto es demostrar que el resultado final es el modo requerido. Si el último resultado no es un modo, cada vez que aparece el modo, se debe "compensar" con un número que no sea el modo, por lo que el número de números que no sean de modo en la matriz no será menor que el número de modos, pero esto No es la realidad Entonces, el algoritmo anterior se establece, tiene una complejidad lineal de tiempo O (n) y una complejidad espacial constante O (1) .

  El código del lenguaje C es básicamente el siguiente:

int find ( int * a, int len) 
{ 
    int i, num = 0, veces = 0; para (i = 0 ; i <len; i ++ ) { if (times> 0 ) { if (num == a [i]) times ++ ; más veces - ; } else { num = a [i]; veces = 1 ; } } return num; }

   Si está escrito en Scheme, el programa puede ser conciso de la siguiente manera:

(define (find s) 
 (car 
  (fold - right 
   (lambda (nr) 
    ( if (zero? (cdr r)) 
     (cons n 1 ) 
     (cons (car r) (( if (eq? n (car r)) + -) (cdr r) 1 ))))
    ' ((). 0) s)))

 

  Problemas después de la actualización

 

  El modo anterior es más de 1/2 de la longitud de la matriz. Si cambia 1/2 a 1/3, ¿cómo lo encuentra?

  Por ejemplo, si la matriz es [1, 1, 2, 3, 4], entonces el modo que se encuentra es 1.

  Sublimamos nuevamente, si es 1 / m, donde m es un parámetro, ¿cómo averiguarlo? Esta pregunta va a ser más complicada que antes. Además, debemos darnos cuenta de que después de que se actualiza el problema, puede haber más de un modo, como [1, 1, 2, 2, 3] la longitud es 5, 1 y 2 son ambos Mayor que 5/3. Hay como máximo modos m-1.

 

  Ideas

 

  Si todavía está ordenado y luego atravesado, sigue siendo válido, pero la complejidad de tiempo sigue siendo el nivel O (nlogn) , todavía esperamos un algoritmo con complejidad de tiempo lineal.

  Para la primera pregunta, la premisa de establecimiento es eliminar dos números diferentes en la matriz, y el modo permanece sin cambios. Entonces, después de la actualización, ¿sigue habiendo un resultado similar? A diferencia de antes, ahora observamos lo que sucede cuando el modo cambia de más de 1/2 a más de 1 / m, y observamos la eliminación de m números diferentes en la matriz a de longitud len. El proceso de prueba es el siguiente:

  Del mismo modo, supongamos que hay un modo x en a, y el número de ocurrencias de x es t. Vea si x no es un modo después de eliminar m números diferentes. Después de eliminar los números m, la nueva matriz tiene una longitud de len-m. x es el modo, por lo que el número de ocurrencias de x es t> len / m. Si no hay xs en los números m eliminados, el número de ocurrencias de x en la matriz restante sigue siendo t, t> len / m> (len-m ) / m, por lo que en este caso x sigue siendo el modo; si hay x en los números m eliminados, porque los números m son diferentes entre sí, entonces solo hay una x, por lo que el número de ocurrencias de x en el conjunto restante es t -1, t> len / m, de modo que t-1> len / m-1 = (len-m) / m, entonces x sigue siendo la mayoría en la matriz restante. Lo anterior es válido para todos los modos en la matriz. Del mismo modo, se puede demostrar que para los números que no están en la matriz, las matrices restantes aún no están en el modo. De hecho, reemplace todo lo anterior con ≤.

  Con el entendimiento anterior, podemos seguir el algoritmo anterior, pero aquí se cambia a una lista vinculada con una longitud de n-1 como máximo. Por ejemplo, para la matriz [1, 2, 1, 3], el modo 1 excede 1/3 de la longitud de la matriz 4, el proceso es el siguiente

  Inicialmente, la lista vacía []

  Recupere el primer elemento 1 y descubra que no hay una entrada con num = 1 en la lista vinculada y que la longitud de la lista vinculada no llega a 2, así que insértela en la lista vinculada y obtenga [(num = 1, veces = 1)]

  Recupere el segundo elemento 2 y descubra que no hay ninguna entrada en la lista vinculada con num = 2, la longitud de la lista vinculada no llega a 2, inserte en la lista vinculada y obtenga [(num = 1, times = 1), (num = 2, times = 1 )]

  Recupere el tercer elemento 1 y descubra que la entrada num = 1 ya existe en la lista vinculada, luego agregue 1 al tiempo de entrada para obtener [(num = 1, times = 2), (num = 2, times = 1)]

  Al recuperar el cuarto elemento 3, se descubre que no hay ningún elemento de tabla num = 3 en la lista vinculada, la longitud de la lista vinculada ha alcanzado el máximo, igual a 2, por lo que se realiza la eliminación, es decir, el tiempo de cada elemento de tabla se reduce en 1 y el elemento de tabla se reduce a 0 Salga de la lista vinculada y obtenga [(num = 1, times = 1)]

  Lo anterior es el proceso, y finalmente el modo es 1.

  La lista vinculada finalmente obtenida por el proceso anterior contiene todos los modos, lo cual es fácil de probar, porque el tiempo de cualquier modo no se puede cancelar por completo. Sin embargo, el proceso anterior no garantiza que la lista final sea todos los modos. Por ejemplo, [1,1,2,3,4] eventualmente obtendrá [(num = 1, times = 1), (num = 4, times = 1)], pero 4 no es un modo.

  Por lo tanto, debemos atravesar nuevamente la matriz después de obtener la lista vinculada y registrar el número de repeticiones en la lista vinculada.

  Python utiliza funciones de orden superior de mapa / reducción para reemplazar bucles de procedimiento. El algoritmo anterior también requiere tanto código de la siguiente manera.

desde la importación de functools reduzca
 def find (a, m):
     def find_index (arr, test):
         para i en rango (len (arr)):
             if test (arr [i]):
                 return i
         return -1
     def check (r, n): 
        index = find_index (r, lambda x: x [0] == n)
         if index> = 0: 
            r [index] [ 1] + = 1
             return r
         if len (r) <m-1 :
             return r + [[n, 1]]
         return reduce ( lambda arr, x: arr if x [1] == 1 else arr + [[x [0], x [1] -1 ]], r, [])
     def count (r, n): 
        index = find_index (r, lambda x: x [0] == n)
         if index < 0:
             return r 
        r [index] [ 1] + = 1
         return r
     return reduce ( lambda r, x: r + [x [0] ] if x [1]> len (a) // m else r, \ 
        reduce (count, a, \ 
            list (map ( lambda x: [x [0], 0], reducir (marcar, a, [])))), [])

 

  Si el código está escrito en lenguaje C, será más, pero no puede usar una lista vinculada, y es mucho más eficiente usar una matriz de longitud fija. Times = 0 significa que los elementos no están ocupados. Esto no se realizará aquí, y dejar que los lectores interesados ​​se den cuenta por sí mismos.

Supongo que te gusta

Origin www.cnblogs.com/Colin-Cai/p/12664044.html
Recomendado
Clasificación