Cómo averiguar la complejidad temporal de un algoritmo dado

Desafortunadamente, no existe un algoritmo para encontrar la complejidad temporal de un algoritmo dado. Ese es el corolario del famoso problema de detención que establece que no existe un algoritmo que responda si un programa terminará, funcionará infinitamente largo. Aparentemente, si pudiéramos encontrar la cantidad de operaciones que realiza el algoritmo, podríamos determinar si se detiene. (Eso es un poco duro, pero espero que tenga sentido)

Por lo tanto, debe encontrar un método específico de algoritmo cada vez. El ejemplo más simple si su programa es solo un montón de bucles for independientes anidados, como estos:

para i en rango (n):
para j en el rango (n):
imprimir (i + j)

La complejidad temporal de este código es [matemática] O (n ^ 2) [/ matemática] porque realiza la impresión exactamente [matemática] n ^ 2, [/ matemática] [matemática] n [/ matemática] veces en cada bucle para [ math] i [/ math] y como hay iteraciones [math] n [/ math] en el primer bucle, lo multiplicamos y obtenemos [math] n ^ 2 [/ math].

Eso fue bastante fácil, pero no es aplicable para la mayoría de las aplicaciones. La forma más general es encontrar biyección entre los estados del algoritmo y algunos objetos combinatorios que es fácil de contar. Permítanme tomar un ejemplo de impresión de todas las secuencias que contienen símbolos [matemáticos] n [/ matemáticos] del conjunto [matemático] \ {0,1 \} [/ matemático] de modo que no haya dos ceros consecutivos. Problemas como ese generalmente se resuelven con recursividad:

def resolver (actual, n):
si len (actual) == n:
imprimir (actual)
más:
resolver (actual + “1”, n)
si len (actual) == 0 o actual [len (actual) -1]! = ‘0’:
resolver (actual + “0”, n)
resolver (“”, n)

Entonces, comenzamos con una cadena vacía e intentamos agregar ceros y unos a su final, verificando si no aparecen dos ceros consecutivos. Existe una obvia biyección entre las operaciones de impresión y el conjunto [matemáticas] S_n = \ left \ {s_1 \ ldots s_n \ colon s_i \ in \ {0,1 \} \, \ land \, \ left (\ forall 1 \ le i <n \ colon (s_i \ neq 0) \ lor (s_ {i + 1} \ neq 0) \ right) \ right \} [/ math] porque ese es exactamente el conjunto de secuencias que queríamos imprimir. Entonces podemos notar que no hay más que [matemáticas] | S_n | \ cdot n [/ math] llamadas de resolución porque para cada impresión había exactamente [math] n [/ math] llamadas de resolución que formaban la secuencia que se imprimió.

Entonces, ¿qué es [matemáticas] | S_n | [/ matemáticas]? Puede notar que cada secuencia en [math] S_n [/ math] termina con 1 o con 10. Más que eso, [math] S_n = \ {s + 1 \ colon s \ en S_ {n-1} \} \ cup \ {s + 10 \ colon s \ en S_ {n-2} \} [/ math]. Entonces [matemáticas] | S_n | = | S_ {n-1} | + | S_ {n-2} | [/ math] y ahora podemos ver que [math] | S_n | = F_ {n + 1} [/ matemática] donde [matemática] F_0 = 0, F_1 ​​= 1, F_i = F_ {i-1} + F_ {i-2} [/ matemática] – números de Fibonacci.

Por lo general, la complejidad del tiempo se escribe en la forma [math] O (\ alpha ^ {f (n)} \ cdot n ^ k) [/ math] donde [math] \ alpha [/ math] y [math] k [/ math ] son ​​constantes. Aquí podemos usar la aproximación para los números de Fibonacci [matemática] F_n = O (\ phi ^ n) [/ matemática] donde [matemática] \ phi = {1 + \ sqrt {5} \ sobre 2} [/ matemática] y obtener el complejidad [matemática] O (\ phi ^ n \ cdot n) [/ matemática]

Bonificación: demuestre que en realidad este código hace que [math] F_2 + F_3 + \ ldots + F_ {n + 1} [/ math] resuelva llamadas que es [math] \ le F_ {n + 3} [/ math].

Piensa en cuántos pasos da .

Te daré algunos ejemplos de trabajo informático. Mejores computadoras son más rápidas. Cuando pones 12 chips gráficos en una computadora, es muy rápido.

La renderización (edición de imagen / video) lleva mucho tiempo porque se deben calcular muchos píxeles.

Operaciones simples como 293 * 827 + 82 que trabajan literalmente en microsegundos.

Los bucles pueden tomar mucho o menos tiempo. (Repetir algo 10,000,000 veces necesita 1000 veces más tiempo que repetir la misma operación 10,000 veces)

Si / else / case / switch es lo mismo que operaciones simples.

Las funciones son solo una línea de código -> rápido (¡y menos código, eso es mejor!)

La carga de una imagen o video es lenta (depende de la conexión: ¡los videos 4K de alta calidad pueden tardar mucho tiempo!)

Cargar algunos códigos de un servidor / base de datos necesita algunos segundos.

Entonces

  • Escribe menos código
  • Escribe un código más eficiente
  • No repitas el código

Buena suerte

Puede consultar el siguiente video sobre la complejidad temporal y espacial de los algoritmos. (Big O, Big Omega y Big Theta se publicarán pronto)

Aquí hay una breve descripción de lo que explica el video:

  • Las operaciones de forma +, -, * /, y, o, &, |, ^, ==, <,>, <=,> =, = se denominan operaciones elementales y se supone que toman una cantidad de tiempo constante .
  • Complejidad de tiempo = kc; donde c es una constante dependiente de la plataforma en la que se ejecuta el algoritmo, k es el número de operaciones elementales que ocurren en función de las variables de entrada al algoritmo.

En el video se han cubierto ejemplos de hacer lo mismo para algún programa.

Sin entrar en la descripción del algoritmo -> Trazando el gráfico entre N y T (N).

de lo contrario-> descubra T (N) por análisis de recuadro blanco. (Esto no se puede automatizar).

More Interesting

¿Qué se siente al resolver bien los problemas de programación dinámica?

¿Está roto el algoritmo de clasificación de Java y Python?

¿Por qué estudiamos diferentes algoritmos para la misma tarea?

¿Cuál es la diferencia entre un gráfico y un árbol en estructuras de datos y algoritmos?

Si tengo una base de datos con 100 mil millones de nombres de usuario, ¿cómo construyo eficientemente una matriz ordenada a partir de eso para realizar fácilmente una búsqueda binaria?

¿Cuál es el algoritmo de Google Map para recomendar rutas?

Cómo mejorar la lógica o la presentación de la conjetura descrita en una respuesta para que más personas puedan entender lo que creo que es un método sorprendente para crear algorítmicamente un conjunto primo potencialmente infinito

¿Cómo difieren la búsqueda lineal y binaria?

¿Cuál es la mejor manera de aprender la estructura de datos y el algoritmo para un programador promedio?

¿Qué es mejor en C #, mantener una variable con un tamaño de matriz o llamar a la longitud de la matriz?

¿Cuáles son algunos problemas de nivel intermedio en los que es imprescindible comprender la corrección de los algoritmos (y por qué)?

¿Cómo funciona este algoritmo para encontrar los bordes del corte mínimo de un gráfico?

¿Cómo se explicaría a un lego el modelo computacional del juego de FIFA?

Quiero escribir un código que reproduzca 10 segundos de audio, luego pause durante 15 segundos y luego reproduzca los siguientes 10 segundos, etc. ¿Cómo lo haría?

Cómo encontrar la mediana de m matrices ordenadas