1. Minimizar un número eliminando K dígitos
Este problema consiste en recibir una cadena que representa un número entero no negativo y un entero k. El objetivo es eliminar exactamente k dígitos de la cadena de tal forma que el número resultante sea el menor posible. Se debe devolver el resultado como una cadena, manejadno correctamente los ceros a la izquierda.
Para resolver esto de manera eficiente, utilizamos una estructura de datos de pila (stack) y un enfoque codicioso (greedy). La idea principal es mantener una secuencia creciente de dígitos en la pila. Si encontramos un dígito menor que el último elemento en la pila mientras aún tenemos "créditos" para eliminar (k > 0), descartamos el elemento superior.
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
pila_digitos = []
for digito in num:
# Mientras el dígito actual sea menor que el tope de la pila,
# eliminamos el tope para intentar formar un número menor.
while k > 0 and pila_digitos and pila_digitos[-1] > digito:
pila_digitos.pop()
k -= 1
pila_digitos.append(digito)
# Si después de recorrer la cadena aún queda k > 0,
# eliminamos los elementos sobrantes del final.
resultado_final = pila_digitos[:-k] if k > 0 else pila_digitos
# Convertimos a cadena y eliminamos ceros iniciales.
salida = "".join(resultado_final).lstrip('0')
return salida if salida else "0"
2. Búsqueda del prefijo común más largo
Dada una lista de cadenas, debemos encontrar la subcadena inicial más larga que sea compartida por todas ellas. Si no existe ningún prefijo común, se devuelve una cadena vacía.
Una técnica eficaz es el escaneo vertical. Comparamos los caracteres de todas las cadenas en la misma posición i. En el momento en que una cadena sea más corta que i o el carácter en esa posición no coincida con el de la primera cadena, habremos encontrado el límite del prefijo.
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
if not strs:
return ""
# Tomamos la primera palabra como referencia
base = strs[0]
for indice in range(len(base)):
caracter_actual = base[indice]
# Comparamos este carácter con el mismo índice en las demás palabras
for j in range(1, len(strs)):
# Si el índice supera la longitud de la palabra o hay discrepancia
if indice == len(strs[j]) or strs[j][indice] != caracter_actual:
return base[:indice]
return base
3. Agrupación de anagramas
Un anagrama es una palabra formada por la reordenación de las letras de otra. El desafío aquí es agrupar una lista de palabras de modo que todos los anagramas queden en la misma sublista.
El método más óptimo utiliza un diccionario (hash map). La clave del diccionario será una representación canónica de la palabra, comúnmente la cadena con sus caracteres orednados alfabéticamente. De esta forma, todas las palabras que sean anagramas entre sí generarán la misma clave.
from collections import defaultdict
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
# Utilizamos defaultdict para evitar errores al inicializar listas vacías
mapa_anagramas = defaultdict(list)
for palabra in strs:
# Ordenamos los caracteres para crear una clave única por grupo
llave_ordenada = "".join(sorted(palabra))
mapa_anagramas[llave_ordenada].append(palabra)
return list(mapa_anagramas.values())