WhatsApp

  

Algoritmo de Partición Entera: Conceptos, Implementación en Python y Mejores Prácticas

Aprende todo sobre el algoritmo de Partición Entera, su teoría, implementaciones en Python (recursiva, memoizada y dinámica), comparativas de rendimiento y casos de uso reales.

Algoritmo de Partición Entera

Generación y conteo de todas las formas de descomponer un número entero positivo en sumas de enteros positivos.

1. ¿Qué es una Partición Entera?

Una partición entera de un número n es una colección de números positivos cuya suma es n. El orden de los sumandos no importa; por ejemplo, 4 = 3+1 = 2+2 = 2+1+1 = 1+1+1+1 son cinco particiones distintas de 4.

Este concepto es fundamental en teoría de números, combinatoria y tiene aplicaciones en criptografía, generación de pruebas de software y optimización de recursos.

2. Enfoques Algorítmicos

2.1 Recursión Simple

Explora todas las posibilidades mediante llamada recursiva. Es sencillo de entender pero tiene complejidad exponencial (O(2ⁿ)) y repite cálculos.

def partition_recursive(n, max_val=None):
    if max_val is None:
        max_val = n
    if n == 0:
        return [[]]
    result = []
    for i in range(min(max_val, n), 0, -1):
        for tail in partition_recursive(n - i, i):
            result.append([i] + tail)
    return result

2.2 Memoización (Recursión con Caché)

Almacena resultados intermedios para evitar recomputaciones, reduciendo la complejidad a O(n·p(n)), donde p(n) es el número de particiones.

from functools import lru_cache
@lru_cache(maxsize=None)
def partition_memo(n, max_val=None):
    if max_val is None:
        max_val = n
    if n == 0:
        return [[]]
    res = []
    for i in range(min(max_val, n), 0, -1):
        for tail in partition_memo(n - i, i):
            res.append([i] + tail)
    return res

2.3 Programación Dinámica (Tabulación)

Construye la solución iterativamente usando una tabla de tamaño (n+1)×(n+1). Es la opción más eficiente para contar particiones y generar todas ellas.

def partition_dp(n):
    # tabla donde dp[i][j] = lista de particiones de i usando valores ≤ j
    dp = [[[] for _ in range(n + 1)] for _ in range(n + 1)]
    dp[0] = [[]]
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if j > i:
                dp[i][j] = dp[i][j - 1]
            else:
                dp[i][j] = dp[i][j - 1] + [[j] + part for part in dp[i - j][j]]
    return dp[n][n]

2.4 Generación con Algoritmo de ZS (Zoghbi‑Stojmenovic)

Un algoritmo iterativo de orden O(p(n)) que genera cada partición en tiempo amortizado constante, ideal para flujos de datos en tiempo real.

def partitions_zs(n):
    a = [0] * (n + 1)
    k = 1
    a[0] = n
    while k != 0:
        x = a[k - 1] - 1
        k -= 1
        while x >= 1:
            a[k] = x
            n -= x
            k += 1
            x = min(x, n)
        a[k] = n
        yield a[:k + 1]

3. Comparativa de Rendimiento

Método Complejidad Temporal Complejidad Espacial Ventajas Desventajas
Recursión Simple O(2ⁿ) O(n) (pila) Fácil de leer, ideal para prototipos. Explosión combinatoria, no apto para n>20.
Memoización O(n·p(n)) O(n·p(n)) (caché) Reduce repeticiones, mantiene claridad recursiva. Consume memoria para n grandes.
Programación Dinámica O(n²) + O(p(n)) O(n²) Determinístico, fácil de depurar, buen balance. Construye tabla completa aunque solo se necesiten algunas particiones.
Algoritmo ZS O(p(n)) (amortizado) O(n) Generación en streaming, bajo consumo de memoria. Implementación más compleja, menos legible.

4. Casos de Uso del Mundo Real

  • Distribución de recursos: dividir un presupuesto o capacidad de almacenamiento entre varios departamentos manteniendo restricciones de tamaño.
  • Pruebas de software: generar combinaciones de datos de entrada para validar algoritmos que operan sobre sumas o particiones.
  • Criptografía: análisis de funciones de partición en esquemas de ocultación de información.
  • Inteligencia Artificial: generación de estructuras de árbol de decisión balanceadas.

5. Buenas Prácticas y Optimización

5.1 Evitar Recursión Profunda

Para n > 30 la recursión simple supera el límite de pila de Python. Utiliza sys.setrecursionlimit() con cautela o prefiere enfoques iterativos.

5.2 Uso de Generadores

Cuando solo necesitas procesar cada partición una vez, emplea yield (como en el algoritmo ZS) para reducir la huella de memoria.

5.3 Cache Distribuida

En entornos de micro‑servicios, almacena resultados parciales en Redis o Memcached para compartir entre instancias.

5.4 Profiling y Benchmarking

Utiliza cProfile y timeit para comparar implementaciones antes de elegir la que mejor se ajuste a tu carga de trabajo.

6. Depuración y Resolución de Problemas Comunes

  • Resultado vacío: Verifica que la condición base sea n == 0 y que el parámetro max_val esté inicializado correctamente.
  • Duplicados: Asegúrate de generar las particiones en orden no creciente (i.e., usar min(max_val, n)) para evitar permutaciones idénticas.
  • Desbordamiento de memoria: Prefiere generadores o la versión tabular con array('I') para almacenar índices en lugar de listas completas.
  • Lentitud inesperada: Revisa que la caché no se esté limpiando frecuentemente y que no haya conversiones costosas de tipos (p.ej., de list a tuple) dentro del bucle.

© 2025 Blog de Algoritmos – Todos los derechos reservados.



Algoritmo de Partición Entera: Conceptos, Implementación en Python y Mejores Prácticas
ASIMOV Ingeniería S. de R.L. de C.V., Emiliano Nava 15 noviembre, 2025
Compartir
Iniciar sesión dejar un comentario

  
Algoritmo de Exponenciación Rápida: Teoría, Implementación en Python y Mejores Prácticas
Aprende a dominar la exponenciación rápida (binary exponentiation) con ejemplos en Python, comparativas de rendimiento, análisis de complejidad, seguridad y trucos de optimización.