sábado, 13 de diciembre de 2025

Parte 2: 10 Ejercicios de Python Nivel Intermedio para Exámenes de Universidad

¿Superaste la Parte 1 sin problemas? Entonces es hora de subir la dificultad. En los exámenes finales de programación no solo basta con saber hacer un bucle; necesitas dominar la búsqueda eficiente, el manejo de errores y la Programación Orientada a Objetos (POO).

Aquí tienes otros 10 enunciados clásicos que tocan temas como Búsqueda Binaria, Ficheros, Herencia y Estructuras de Datos optimizadas.


11. Búsqueda Binaria (Binary Search)

El Enunciado: Dada una lista ordenada, encontrar la posición de un número objetivo. Si no existe, devolver -1. Debes hacerlo con una complejidad O(log n), no lineal.

def busqueda_binaria(lista, objetivo):
    izquierda = 0
    derecha = len(lista) - 1

    while izquierda <= derecha:
        medio = (izquierda + derecha) // 2
        
        if lista[medio] == objetivo:
            return medio # Encontrado
        elif lista[medio] < objetivo:
            izquierda = medio + 1
        else:
            derecha = medio - 1
            
    return -1 # No encontrado

numeros = [1, 3, 5, 7, 9, 11, 15]
print(busqueda_binaria(numeros, 9)) # Salida: 4 (índice)

12. Lectura de Archivos y Conteo de Líneas

El Enunciado: Escribe una función que lea un archivo de texto (ej. "datos.txt") y cuente cuántas líneas tiene. Debes manejar la posibilidad de que el archivo no exista.

def contar_lineas(nombre_archivo):
    try:
        with open(nombre_archivo, 'r') as archivo:
            lineas = archivo.readlines()
            return len(lineas)
    except FileNotFoundError:
        return "Error: El archivo no existe."

# Nota: Necesitas crear un archivo 'notas.txt' para probarlo
# print(contar_lineas("notas.txt"))

13. Herencia en Clases (POO)

El Enunciado: Crea una clase Persona y una clase hija Empleado. El empleado debe heredar el nombre de la persona y añadir un atributo salario.

class Persona:
    def __init__(self, nombre, edad):
        self.nombre = nombre
        self.edad = edad

class Empleado(Persona):
    def __init__(self, nombre, edad, salario):
        # Llamamos al constructor de la clase padre
        super().__init__(nombre, edad) 
        self.salario = salario

    def mostrar_datos(self):
        return f"Emp: {self.nombre}, Salario: ${self.salario}"

admin = Empleado("Ana", 30, 2500)
print(admin.mostrar_datos())

14. Eliminar duplicados de una lista

El Enunciado: Dada una lista con elementos repetidos, devolver una nueva lista con los elementos únicos (sin usar bucles anidados excesivos).

def eliminar_duplicados(lista):
    # Convertir a set elimina duplicados automáticamente
    # Luego volvemos a convertir a lista
    return list(set(lista))

items = [1, 2, 2, 3, 4, 4, 4, 5]
print(eliminar_duplicados(items))
# Salida: [1, 2, 3, 4, 5] (El orden puede variar)

15. Anagramas

El Enunciado: Determinar si dos cadenas de texto son anagramas (contienen exactamente las mismas letras en diferente orden).

def son_anagramas(palabra1, palabra2):
    # Ordenamos las letras y comparamos
    return sorted(palabra1.lower()) == sorted(palabra2.lower())

print(son_anagramas("Roma", "Amor")) # True
print(son_anagramas("Casa", "Caza")) # False

16. Comprensión de Listas con Condicionales

El Enunciado: Dada una lista de números, crear una nueva lista que contenga solo los números pares elevados al cuadrado, utilizando una sola línea de código.

numeros = [1, 2, 3, 4, 5, 6]

# Sintaxis: [expresion for item in lista if condicion]
cuadrados_pares = [x**2 for x in numeros if x % 2 == 0]

print(cuadrados_pares)
# Salida: [4, 16, 36] (2^2, 4^2, 6^2)

17. Diccionario de Listas (Agrupación)

El Enunciado: Tienes una lista de tuplas (alumno, materia). Crea un diccionario donde la clave sea la materia y el valor sea una lista de alumnos inscritos en ella.

datos = [("Juan", "Mate"), ("Ana", "Física"), ("Luis", "Mate")]

def agrupar_por_materia(datos):
    grupo = {}
    for alumno, materia in datos:
        if materia not in grupo:
            grupo[materia] = []
        grupo[materia].append(alumno)
    return grupo

print(agrupar_por_materia(datos))
# Salida: {'Mate': ['Juan', 'Luis'], 'Física': ['Ana']}

18. La Suma de Dos (Two Sum)

El Enunciado: Dada una lista de números y un valor objetivo, encuentra los índices de los dos números que suman ese valor.

def two_sum(nums, target):
    vistos = {} # Valor: Índice
    for i, num in enumerate(nums):
        complemento = target - num
        if complemento in vistos:
            return [vistos[complemento], i]
        vistos[num] = i

print(two_sum([2, 7, 11, 15], 9))
# Salida: [0, 1] (porque 2 + 7 = 9)

19. Generadores (Yield)

El Enunciado: Escribe una función generadora que produzca una secuencia de números pares hasta un límite dado, para ahorrar memoria.

def generar_pares(limite):
    num = 0
    while num < limite:
        yield num
        num += 2

# Uso del generador
for par in generar_pares(10):
    print(par, end=" ")
# Salida: 0 2 4 6 8

20. Manejo de Excepciones: División Segura

El Enunciado: Crea una función que divida dos números. Debe controlar si el usuario introduce texto en lugar de números o si intenta dividir por cero.

def division_segura(a, b):
    try:
        resultado = float(a) / float(b)
        return resultado
    except ZeroDivisionError:
        return "Error: No puedes dividir por 0"
    except ValueError:
        return "Error: Debes introducir números"

print(division_segura(10, 0)) # Error controlado
print(division_segura(10, "dos")) # Error controlado

Conclusión Parte 2

Si eres capaz de resolver estos ejercicios sin mirar la solución, ¡felicidades! Estás muy por encima de la media. Estos conceptos (especialmente diccionarios, manejo de errores y clases) son el pan de cada día en el mundo profesional.

¿Quieres seguir avanzando? Lo próximo sería entrar en estructuras de datos avanzadas como Árboles Binarios o algoritmos de grafos. ¡Dímelo en los comentarios si quieres una Parte 3!

No hay comentarios:

Publicar un comentario