Ir al contenido principal

Actualización de «Máxima suma de los segmentos»

He actualizado las soluciones del ejercicio «Máxima suma de los segmentos» cuyo enunciado es


Un segmento de una lista xs es una sublista de xs formada por elementos consecutivos en la lista. El problema de la máxima suma de segmentos consiste en dada una lista de números enteros calcular el máximo de las sumas de todos los segmentos de la lista. Por ejemplo, para la lista [-1,2,-3,5,-2,1,3,-2,-2,-3,6] la máxima suma de segmentos es 7 que es la suma del segmento [5,-2,1,3] y para la lista [-1,-2,-3] es 0 que es la suma de la lista vacía.

Definir la función

mss :: [Integer] -> Integer

tal que (mss xs) es la máxima suma de los segmentos de xs. Por ejemplo,

mss [-1,2,-3,5,-2,1,3,-2,-2,-3,6]  ==  7
mss [-1,-2,-3]                     ==  0
mss [1..500]                       ==  125250
mss [1..1000]                      ==  500500
mss [-500..3]                      ==  6
mss [-1000..3]                     ==  6
mss [1..10^2]                      ==  5050
mss [1..10^3]                      ==  500500
mss [1..10^4]                      ==  50005000
mss [1..10^5]                      ==  5000050000
mss [1..10^6]                      ==  500000500000
mss [1..10^7]                      ==  50000005000000

Nota: Puedes consultar las soluciones aquí.

Actualización de «Listas disjuntas»

He actualizado las soluciones del ejercicio «Listas disjuntas» cuyo enunciado es


Definir la función

disjuntas :: Ord a => [a] -> [a] -> Bool

tal que (disjuntas xs ys) se verifica si las listas ordenadas crecientemente xs e ys son disjuntas. Por ejemplo,

disjuntas [2,5]   [1,4,7]                  ==  True
disjuntas [2,5,7] [1,4,7]                  ==  False
disjuntas [1..1000000] [3000000..4000000]  ==  True

Nota: Puedes consultar las soluciones aquí.

Actualización de «Triángulos de Herón»

He actualizado las soluciones del ejercicio «Triángulos de Herón» cuyo enunciado es


Un triángulo de Herón es un triángulo tal que sus lados y su área son números enteros. Su nombre se debe al matemático griego Herón de Alejandría que descubrió la fórmula para calcular el área de un triángulo a partir de sus lados.

La fórmula de Herón dice que el área de un triángulo cuyos lados miden \(a\), \(b\) y \(c\) es \[\sqrt{s(s-a)(s-b)(s-c)}\] donde \(s\) es el semiperímetro del triángulo; es decir, \[s=\frac{a+b+c}{2}\]

Un ejemplo de triángulo de Herón es el triángulo de lados 3, 4 y 5 cuya área es 6. Se puede observar que cualquier triángulo cuyos lados sean múltiplos de 3, 4 y 5 también es de Herón; por ejemplo, el de lados 6, 8 y 10 también lo es.

Se dice que un triángulo de Herón es primitivo si el máximo común divisor de sus lados es 1. Por ejemplo, el de lados 3, 4 y 5 es primitivo; pero el de lados 6, 8 y 10 no lo es.

Definir la sucesión

triangulosHeronPrimitivos :: [(Int,Int,Int)]

tal que sus elementos son los triángulos de Herón primitivos ordenados por su perímetro. Por ejemplo,

λ> take 7 triangulosHeronPrimitivos
[(3,4,5),(5,5,6),(5,5,8),(5,12,13),(4,13,15),(10,13,13),(9,10,17)]
λ> triangulosHeronPrimitivos !! 1000
(212,225,247)

Nota: Puedes consultar las soluciones aquí.

Actualización de «2015 y los números pitagóricos»

He actualizado las soluciones del ejercicio «2015 y los números pitagóricos» cuyo enunciado es


Un número pitagórico es un número natural cuyo cuadrado se puede escribir como la suma de los cuadrados de dos números naturales no nulos; es decir, el número natural a es pitagórico si existen dos números naturales b y c distintos de cero tales que a² = b²+c². Por ejemplo, 5 es un número pitagórico ya que 5² = 3²+4² y también lo es 2015 ya que 2015² = 1612²+1209².

Definir la sucesión

pitagoricos :: [Integer]

cuyos elementos son los números pitagóricos. Por ejemplo,

λ> take 20 pitagoricos
[5,10,13,15,17,20,25,26,29,30,34,35,37,39,40,41,45,50,51,52]
λ> pitagoricos !! 50000
73035

Calcular la posición de 2015 en la sucesión.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Simplificación de expresiones proposicionales»

He actualizado las soluciones del ejercicio «Simplificación de expresiones proposicionales» cuyo enunciado es


El siguiente tipo de dato algebraico representa las fórmulas proposicionales construidas con una variable (X), las constantes verdadera (V) y falsa (F), la negación (Neg) y la disyunción (Dis):

data Form = X
          | V
          | F
          | Neg Form
          | Dis Form Form
  deriving (Eq, Ord, Show)

Por ejemplo, la fórmula (¬X v V) se representa por (Dis (Neg X) V).

Definir las funciones

valor      :: Form -> Bool -> Bool
simplifica :: Form -> Form

tales que

  • (valor p i) es el valor de la fórmula p cuando se le asigna a X el valor i. Por ejemplo,
valor (Neg X) True           ==  False
valor (Neg F) True           ==  True
valor (Dis X (Neg X)) True   ==  True
valor (Dis X (Neg X)) False  ==  True
  • (simplifica p) es una forma obtenida aplicándole a p las siguientes reglas de simplificación:
Neg V       = F
Neg F       = V
Neg (Neg q) = q
Dis V q     = V
Dis F q     = q
Dis q V     = V
Dis q F     = F
Dis q q     = q

Por ejemplo,

simplifica (Dis X (Neg (Neg X)))                      ==  X
simplifica (Neg (Dis (Neg (Neg X)) F))                ==  Neg X
simplifica (Dis (Neg F) F)                            ==  V
simplifica (Dis (Neg V) (Neg (Dis (Neg X) F)))        ==  X
simplifica (Dis (Neg V) (Neg (Dis (Neg (Neg X)) F)))  ==  Neg X

Comprobar con QuickCheck que para cualquier fórmula p y cualquier booleano i se verifica que (valor (simplifica p) i) es igual a (valor p i).


Nota: Puedes consultar las soluciones aquí.

Actualización de «2015 y los números con factorización capicúa»

He actualizado las soluciones del ejercicio «2015 y los números con factorización capicúa» cuyo enunciado es


Un número tiene factorización capicúa si puede escribir como un producto de números primos tal que la concatenación de sus dígitos forma un número capicúa. Por ejemplo, el 2015 tiene factorización capicúa ya que \(2015 = 13 \times 5 \times 31\), los factores son primos y su concatenación es 13531 que es capicúa.

Definir la sucesión

conFactorizacionesCapicuas :: [Int]

formada por los números que tienen factorización capicúa. Por ejemplo,

λ> take 20 conFactorizacionesCapicuas
[1,2,3,4,5,7,8,9,11,12,16,18,20,25,27,28,32,36,39,44]
λ> conFactorizacionesCapicuas !! 3000
91019

Usando conFactorizacionesCapicuas escribir expresiones cuyos valores sean las respuestas a las siguientes preguntas y calcularlas

  1. ¿Qué lugar ocupa el 2015 en la sucesión?
  2. ¿Cuál fue el anterior año con factorización capicúa?
  3. ¿Cuál será el siguiente año con factorización capicúa?

Nota: Puedes consultar las soluciones aquí.

Actualización de «Período de una lista»

He actualizado las soluciones del ejercicio «Período de una lista» cuyo enunciado es


El período de una lista xs es la lista más corta ys tal que xs se puede obtener concatenando varias veces la lista ys. Por ejemplo, el período "abababab" es "ab" ya que "abababab" se obtiene repitiendo tres veces la lista "ab".

Definir la función

periodo :: Eq a => [a] -> [a]

tal que (periodo xs) es el período de xs. Por ejemplo,

periodo "ababab"      ==  "ab"
periodo "buenobueno"  ==  "bueno"
periodo "oooooo"      ==  "o"
periodo "sevilla"     ==  "sevilla"

Nota: Puedes consultar las soluciones aquí.

Actualización de «La función suelo»

He actualizado las soluciones del ejercicio «La función suelo» cuyo enunciado es


La función suelo asigna a cada número real el número entero más próximo por defecto; es decir, el mayor número entero igual o menor que ese número real. Por ejemplo, al -2.4 le asigna el -3 y al 1.7 el 1.

Haskell tiene una implementación de la función suelo llamada floor. El objetivo de este ejercicio es redefinir dicha función; es decir, definir la función

suelo :: Float -> Integer

tal que (suelo x) es el suelo de x. Por ejemplo,

suelo (-2.7)  ==  -3
suelo (-2.4)  ==  -3
suelo (-2)    ==  -2
suelo 0       ==   0
suelo 2       ==   2
suelo 2.4     ==   2
suelo 2.7     ==   2

Comprobar con QuickCheck que las funciones suelo y floor son equivalentes.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Enumeración de los pares de números naturales»

He actualizado las soluciones del ejercicio «Enumeración de los pares de números naturales» cuyo enunciado es


Los pares de los números naturales se pueden ordenar por la suma de sus componentes y entres los pares con la misma suma elegir antes al que tiene mayor su primera componente.

Definir las funciones

pares    :: [(Int,Int)]
posicion :: (Int,Int) -> Int

tales que

  • pares es la lista de los pares de números naturales con el orden anterior. Por ejemplo,
λ> take 10 pares
[(0,0),(1,0),(0,1),(2,0),(1,1),(0,2),(3,0),(2,1),(1,2),(0,3)]
  • (posicion p) es la posición del par p en la lista pares. Por ejemplo,
posicion (0,0)  ==  0
posicion (2,0)  ==  3

Nota: Puedes consultar las soluciones aquí.

Actualización de «Elementos más frecuentes»

He actualizado las soluciones del ejercicio «Elementos más frecuentes» cuyo enunciado es


Definir la función

masFrecuentes :: Ord a => Int -> [a] -> [(Int,a)]

tal que (masFrecuentes n xs) es la lista de los pares formados por n elementos de xs que aparecen más veces junto con el número de veces que aparecen. Por ejemplo,

λ> masFrecuentes 2 "trianera"
[(2,'r'),(2,'a')]
λ> masFrecuentes 2 "interdisciplinariedad"
[(5,'i'),(3,'d')]
λ> masFrecuentes 3 (show (product [1..10000]))
[(5803,'0'),(3416,'2'),(3341,'4')]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Puntos en regiones rectangulares»

He actualizado las soluciones del ejercicio «Puntos en regiones rectangulares» cuyo enunciado es


Los puntos se puede representar mediante pares de números

type Punto = (Float,Float)

y las regiones rectangulares mediante el siguiente tipo de dato

data Region = Rectangulo Punto  Punto
            | Union      Region Region
            | Diferencia Region Region
            deriving (Eq, Show)

donde

  • (Rectangulo p1 p2) es la región formada por un rectángulo cuyo vértice superior izquierdo es p1 y su vértice inferior derecho es p2.
  • (Union r1 r2) es la región cuyos puntos pertenecen a alguna de las regiones r1 o r2.
  • (Diferencia r1 r2) es la región cuyos puntos pertenecen a la región r1 pero no pertenecen a la r2.

Definir la función

enRegion :: Punto -> Region -> Bool

tal que (enRegion p r) se verifica si el punto p pertenece a la región r. Por ejemplo, usando las regiones definidas por

r0021, r3051, r4162 :: Region
r0021 = Rectangulo (0,0) (2,1)
r3051 = Rectangulo (3,0) (5,1)
r4162 = Rectangulo (4,1) (6,2)

se tiene

enRegion (1.6,0.7) r0021                               ==  True
enRegion (3.6,0.7) r0021                               ==  False
enRegion (1,1) (Union r0021 r3051)                     ==  True
enRegion (4,0) (Union r0021 r3051)                     ==  True
enRegion (4,2) (Union r0021 r3051)                     ==  False
enRegion (3,1) (Diferencia r3051 r4162)                ==  True
enRegion (4,1) (Diferencia r3051 r4162)                ==  False
enRegion (4,2) (Diferencia r3051 r4162)                ==  False
enRegion (4,2) (Union (Diferencia r3051 r4162) r4162)  ==  True

Comprobar con QuickCheck que si el punto p está en la región r1, entonces, para cualquier región r2, p está en (Union r1 r2) y en (Union r2 r1), pero no está en (Diferencia r2 r1).


Nota: Puedes consultar las soluciones aquí.

Actualización de «Desemparejamiento de listas»

He actualizado las soluciones del ejercicio «Desemparejamiento de listas» cuyo enunciado es


Definir la función

desemparejada :: [(a,b)] -> ([a],[b])

tal que (desemparejada ps) es el par de lista (xs,ys) tal que al emparejar (con zip) xs e ys devuelve ps. Por ejemplo,

λ> desemparejada [(3,'l'),(2,'u'),(5,'i'),(9,'s')]
([3,2,5,9],"luis")

Comprobar con QuickCheck que

  • desemparejada es equivalente a la función predefinida unzip.
  • si el valor de (desemparejada ps) es (xs,ys), entonces (zip xs ys) es igual a ps.

Nota: Puedes consultar las soluciones aquí.

Actualización de «2015 y los números tales que la suma de sus dígitos es igual al número de sus divisores»

He actualizado las soluciones del ejercicio «2015 y los números tales que la suma de sus dígitos es igual al número de sus divisores» cuyo enunciado es


Una propiedad del 2015 es que la suma de sus dígitos coincide con el número de sus divisores; en efecto, la suma de sus dígitos es 2+0+1+5=8 y tiene 8 divisores (1, 5, 13, 31, 65, 155, 403 y 2015).

Definir la sucesión

especiales :: [Int]

formada por los números n tales que la suma de los dígitos de n coincide con el número de divisores de n. Por ejemplo,

λ> take 15 especiales
[1,2,11,22,36,84,101,152,156,170,202,208,225,228,288]
λ> length (takeWhile (<300000) especiales)
4305

Usar la sucesión para responder las siguientes cuestiones

  • ¿Cuántos años hasta el 2015 inclusive han cumplido la propiedad?
  • ¿Cuál fue el anterior al 2015 que cumplió la propiedad?
  • ¿Cuál será el siguiente al 2015 que cumplirá la propiedad?

Nota: La sucesión especiales es la misma que la A057531 de la OEIS (On-Line Encyclopedia of Integer Sequences).


Nota: Puedes consultar las soluciones aquí.

Actualización de «2015 como raíz cuadrada de la suma de tres cubos»

He actualizado las soluciones del ejercicio «2015 como raíz cuadrada de la suma de tres cubos» cuyo enunciado es


Todos los años, en las proximidades del final de año suelen aparecer cuestiones con propiedades del número del nuevo año. Una sobre el 2015 es la publicada el martes en la entrada 2015 como raíz de la suma de tres cubos del blog Números y algo más en la que se pide calcular tres números tales que 2015 sea igual a la raíz cuadrada de la suma de dichos tres números.

A partir de dicha entrada, se propone el siguiente problema: Definir la sucesión

raicesCuadradasDeSumasDe3Cubos :: [Integer]

cuyos elementos son los números que se pueden escribir como raíces cuadradas de sumas de tres cubos. Por ejemplo,

λ> take 9 raicesCuadradasDeSumasDe3Cubos
[6,9,15,27,48,53,59,71,72]
λ> raicesCuadradasDeSumasDe3Cubos !! 100
672

El 6 está en la sucesión porque 1³+2³+3³ = 36 y la raíz cuadrada de36 es 6 y el 9 está porque 3³+3³+3³ = 81 y la raíz cuadrada de 81 es 9. Algunos números tienen varias descomposiones como raíz cuadrada de suma de tres cubos; por ejemplo, el 71 se puede escribir como la raíz cuadrada de la suma de los cubos de 6, 9 y 16 y también como la de 4, 4, y 17.

A partir de la sucesión se plantean las siguientes cuestiones:

  • ¿Qué lugar ocupa el 2015 en la sucesión?
  • ¿Cuál será el próximo año que se podrá escribir como la raíz cuadrada de suma de tres cubos?
  • ¿Cuáles son las descomposiciones de 2015 como raíz cuadrada de suma de tres cubos?
  • ¿Cuáles son los años hasta el 2015 que se pueden escribir como raíz cuadrada de suma de tres cubos de más formas distintas?

Nota: Puedes consultar las soluciones aquí.

Actualización de «Elementos adicionales»

He actualizado las soluciones del ejercicio «Elementos adicionales» cuyo enunciado es


Definir la función

adicionales :: Ord a => Int -> [a] -> [a] -> [a]

tal que (adicionales n xs ys) es la lista de los n elementos de xs que no pertenecen a ys (se supone que n es el número de elementos de xs que no pertenecen a ys, que las listas xs e ys están estrictamente ordenadas y que pueden ser infinitas). Por ejemplo,

adicionales 0 [1,3]   [1,3]                  ==  []
adicionales 1 [1,3]   [1]                    ==  [3]
adicionales 2 [1,3,5] [1]                    ==  [3,5]
adicionales 2 [1,3,5,7,9] [1,5,7]            ==  [3,9]
adicionales 2 ([1,3,5]++[7..]) ([1]++[7..])  ==  [3,5]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Representaciones de matrices»

He actualizado las soluciones del ejercicio «Representaciones de matrices» cuyo enunciado es


Las matrices se pueden representar de distintas formas. Por ejemplo, la matriz

|7 5 6|
|1 9 4|

se puede representar como la terna

([7,5,6,1,9,4],2,3)

(donde la primera componente es la lista de los elementos de matriz, la segunda es su número de filas y la tercera es su número de columnas) y también se puede representar como una lista de listas

[[[7,5,6],[1,9,4]]

(donde cada elemento es una de las filas de la matriz).

Definir las funciones

ternaAlistas :: ([a],Int,Int) -> [[a]]
listasAterna :: [[a]] -> ([a],Int,Int)

tales que ternaAlistas pase de la primera representación a la segunda y listasAterna pase de la segunda a la primera. Por ejemplo,

ternaAlistas ([7,5,6,1,9,4],2,3)  ==  [[7,5,6],[1,9,4]]
listasAterna [[7,5,6],[1,9,4]]    ==  ([7,5,6,1,9,4],2,3)
ternaAlistas ([7,5,6,1,9,4],3,2)  ==  [[7,5],[6,1],[9,4]]
listasAterna [[7,5],[6,1],[9,4]]  ==  ([7,5,6,1,9,4],3,2)

Nota: Puedes consultar las soluciones aquí.

Actualización de «Permutación de elementos consecutivos»

He actualizado las soluciones del ejercicio «Permutación de elementos consecutivos» cuyo enunciado es


Definir la función

permutaConsecutivos :: [a] -> [a]

tal que (permutaConsecutivos xs) es la lista obtenida permutando los elementos consecutivos de xs. Por ejemplo,

permutaConsecutivos [1..8]         ==  [2,1,4,3,6,5,8,7]
permutaConsecutivos [1..9]         ==  [2,1,4,3,6,5,8,7,9]
permutaConsecutivos "simplemente"  ==  "ispmelemtne"

Nota: Puedes consultar las soluciones aquí.

Actualización de «Juego de bloques con letras»

He actualizado las soluciones del ejercicio «Juego de bloques con letras» cuyo enunciado es


Para el juego de los bloques se dispone de un conjunto de bloques con una letra en cada una de sus dos caras. El objetivo del juego consiste en formar palabras sin que se pueda usar un bloque más de una vez y sin diferenciar mayúsculas de minúsculas. Por ejemplo, si se tiene tres bloques de forma que el 1º tiene las letras A y B, el 2ª la N y la O y el 3º la O y la A entonces se puede obtener la palabra ANA de dos formas: una con los bloques 1, 2 y 3 y otra con los 3, 2 y 1.

Definir la función

soluciones :: [String] -> String -> [[String]]

tal que (soluciones bs cs) es la lista de las soluciones del juego de los bloque usando los bloques bs (cada bloque es una cadena de dos letras mayúsculas) para formar la palabra cs. Por ejemplo,

λ> soluciones ["AB","NO","OA"] "ANA"
[["AB","NO","OA"],["OA","NO","AB"]]
λ> soluciones ["AB","NE","OA"] "Bea"
[["AB","NE","OA"]]
λ> soluciones ["AB","NE","OA"] "EvA"
[]
λ> soluciones ["AB","NO","OA","NC"] "ANA"
[["AB","NO","OA"],["AB","NC","OA"],["OA","NO","AB"],["OA","NC","AB"]]
λ> soluciones ["AB","NO","OA","NC"] "Anca"
[["AB","NO","NC","OA"],["OA","NO","NC","AB"]]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Números que sumados a su siguiente primo dan primos»

He actualizado las soluciones del ejercicio «Números que sumados a su siguiente primo dan primos» cuyo enunciado es


La Enciclopedia electrónica de sucesiones de enteros (OEIS por sus siglas en inglés, de On-Line Encyclopedia of Integer Sequences) es una base de datos que registra sucesiones de números enteros. Está disponible libremente en Internet, en la dirección http://oeis.org.

La semana pasada Antonio Roldán añadió una nueva sucesión a la OEIS, la A249624 que sirve de base para el problema de hoy.

Definir la sucesión

a249624 :: [Integer]

tal que sus elementos son los números x tales que la suma de x y el primo que le sigue es un número primo. Por ejemplo,

λ> take 20 a249624
[0,1,2,6,8,14,18,20,24,30,34,36,38,48,50,54,64,68,78,80]

El número 8 está en la sucesión porque su siguiente primo es 11 y 8+11=19 es primo. El 12 no está en la sucesión porque su siguiente primo es 13 y 12+13=25 no es primo.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Normalización de expresiones aritméticas»

He actualizado las soluciones del ejercicio «Normalización de expresiones aritméticas» cuyo enunciado es


El siguiente tipo de dato representa expresiones construidas con variables, sumas y productos

data Expr = V String
          | S Expr Expr
          | P Expr Expre
  deriving (Eq, Show)

Por ejemplo, x*(y+z) se representa por (P (V "x") (S (V "y") (V "z")))

Una expresión es un término si es un producto de variables. Por ejemplo, x*(y*z) es un término pero x+(y*z) ni x*(y+z) lo son.

Una expresión está en forma normal si es una suma de términos. Por ejemplo, x*(y*z) y x+(y*z) están en forma normal; pero x*(y+z) y (x+y)*(x+z) no lo están.

Definir la función

esTermino :: Expr -> Bool
esNormal  :: Expr -> Bool
normal    :: Expr -> Expr

tales que

  • (esTermino a) se verifica si a es un término. Por ejemplo,
esTermino (V "x")                         == True
esTermino (P (V "x") (P (V "y") (V "z"))) == True
esTermino (P (V "x") (S (V "y") (V "z"))) == False
esTermino (S (V "x") (P (V "y") (V "z"))) == False
  • (esNormal a) se verifica si a está en forma normal. Por ejemplo,
esNormal (V "x")                                     == True
esNormal (P (V "x") (P (V "y") (V "z")))             == True
esNormal (S (V "x") (P (V "y") (V "z")))             == True
esNormal (P (V "x") (S (V "y") (V "z")))             == False
esNormal (P (S (V "x") (V "y")) (S (V "y") (V "z"))) == False
esNormal (S (P (V "x") (V "y")) (S (V "z") (V "x"))) == True
  • (normal e) es la forma normal de la expresión e obtenida aplicando, mientras que sea posible, las propiedades distributivas ((a+b)·c = a·c+b·c y c·(a+b) = c·a+c·b). Por ejemplo,
λ> normal (P (S (V "x") (V "y")) (V "z"))
S (P (V "x") (V "z")) (P (V "y") (V "z"))
λ> normal (P (V "z") (S (V "x") (V "y")))
S (P (V "z") (V "x")) (P (V "z") (V "y"))
λ> normal (P (S (V "x") (V "y")) (S (V "u") (V "v")))
S (S (P (V "x") (V "u")) (P (V "x") (V "v")))
   (S (P (V "y") (V "u")) (P (V "y") (V "v")))
λ> normal (S (P (V "x") (V "y")) (V "z"))
S (P (V "x") (V "y")) (V "z")
λ> normal (V "x")
V "x"

Comprobar con QuickCheck que para cualquier expresión e, (normal e) está en forma normal y que (normal (normal e)) es igual a (normal e).


Nota: Puedes consultar las soluciones aquí.

Actualización de «Sin consecutivos repetidos»

He actualizado las soluciones del ejercicio «Sin consecutivos repetidos» cuyo enunciado es


Definir la función

sinConsecutivosRepetidos :: Eq a => [a] -> [a]

tal que (sinConsecutivosRepetidos xs) es la lista obtenida a partir de xs de forma que si hay dos o más elementos idénticos consecutivos, borra las repeticiones y deja un elemento. Por ejemplo,

λ> sinConsecutivosRepetidos "eesssooo essss   toodddooo"
"eso es todo"

Nota: Puedes consultar las soluciones aquí.

Actualización de «Búsqueda en lista de listas de pares»

He actualizado las soluciones del ejercicio «Búsqueda en lista de listas de pares» cuyo enunciado es


Definir la función

busca :: Eq a => a -> [[(a,b)]] -> [b]

tal que (busca x pss) es la lista de los segundos componentes de los pares de la lista de listas de pares pss cuya primera componentes es x. Por ejemplo,

busca 3 [[(3,4)],[(5,4),(3,2),(3,5)],[(4,1),(7,3)]] == [4,2,5]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Problema de las puertas»

He actualizado las soluciones del ejercicio «Problema de las puertas» cuyo enunciado es


Un hotel dispone de n habitaciones y n camareros. Los camareros tienen la costumbre de cambiar de estado las puestas (es decir, abrir las cerradas y cerrar las abiertas). El proceso es el siguiente:

  • Inicialmente todas las puertas están cerradas.
  • El primer camarero cambia de estado las puertas de todas las habitaciones.
  • El segundo cambia de estado de las puertas de las habitaciones pares.
  • El tercero cambia de estado todas las puertas que son múltiplos de 3.
  • El cuarto cambia de estado todas las puertas que son múltiplos de 4
  • Así, hasta que ha pasado el último camarero.

Por ejemplo, para n = 5

Pase    | Puerta 1 | Puerta 2 | Puerta 3 | Puerta 4 | Puerta 5
--------+----------+----------+----------+----------+---------
Inicial | Cerrada  | Cerrada  | Cerrada  | Cerrada  | Cerrada
Pase 1  | Abierta  | Abierta  | Abierta  | Abierta  | Abierta
Pase 2  | Abierta  | Cerrada  | Abierta  | Cerrada  | Abierta
Pase 3  | Abierta  | Cerrada  | Cerrada  | Cerrada  | Abierta
Pase 4  | Abierta  | Cerrada  | Cerrada  | Abierta  | Abierta
Pase 5  | Abierta  | Cerrada  | Cerrada  | Abierta  | Cerrada

Los estados de las puertas se representan por el siguiente tipo de datos

data Estado = Abierta | Cerrada
  deriving (Eq, Show)

Definir la función

final :: Int -> [Estado]

tal que (final n) es la lista de los estados de las n puertas después de que hayan pasado los n camareros. Por ejemplo,

λ> final 5
[Abierta,Cerrada,Cerrada,Abierta,Cerrada]
λ> final 7
[Abierta,Cerrada,Cerrada,Abierta,Cerrada,Cerrada,Cerrada]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Llanuras de longitud dada»

He actualizado las soluciones del ejercicio «Llanuras de longitud dada» cuyo enunciado es


Una llanura de longitud n de una lista xs es una sublista de xs formada por n elementos iguales.

Definir la función

llanuras :: Eq a => Int -> [a] -> [[a]]

tal que (llanuras n xs) es la lista de las llanuras de xs que tienen n elementos como mínimo. Por ejemplo,

llanuras 3 "aabbbcddddffxffxx"  ==  ["bbb","dddd"]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Expresiones vectoriales»

He actualizado las soluciones del ejercicio Expresiones vectoriales cuyo enunciado es


El siguiente tipo de dato define las expresiones vectoriales formadas por un vector, la suma de dos expresiones vectoriales o el producto de un entero por una expresión vectorial.

data ExpV = Vec Int Int
          | Sum ExpV ExpV
          | Mul Int ExpV
  deriving Show

Definir la función

valor :: ExpV -> (Int,Int)

tal que (valor e) es el valor de la expresión vectorial e. Por ejemplo,

valor (Vec 1 2)                                  ==  (1,2)
valor (Sum (Vec 1 2 ) (Vec 3 4))                 ==  (4,6)
valor (Mul 2 (Vec 3 4))                          ==  (6,8)
valor (Mul 2 (Sum (Vec 1 2 ) (Vec 3 4)))         ==  (8,12)
valor (Sum (Mul 2 (Vec 1 2)) (Mul 2 (Vec 3 4)))  ==  (8,12)

Nota: Puedes consultar las soluciones aquí.

Actualización de «Expresiones aritmética normalizadas»

He actualizado las soluciones del ejercicio Expresiones aritmética normalizadas cuyo enunciado es


El siguiente tipo de dato representa expresiones construidas con variables, sumas y productos

data Expr = Var String
          | S Expr Expr
          | P Expr Expre
  deriving Show

Por ejemplo, x.(y+z) se representa por (P (V "x") (S (V "y") (V "z"))).

Una expresión es un término si es un producto de variables. Por ejemplo, x.(y.z) es un término pero x+(y.z) ni x.(y+z) lo son.

Una expresión está en forma normal si es una suma de términos. Por ejemplo, x.(y,z) y x+(y.z) está en forma normal; pero x.(y+z) y (x+y).(x+z) no lo están.

Definir las funciones

esTermino :: Expr -> Bool
esNormal  :: Expr -> Bool

tales que

  • (esTermino a) se verifica si a es un término. Por ejemplo,
esTermino (V "x")                                    == True
esTermino (P (V "x") (P (V "y") (V "z")))            == True
esTermino (P (V "x") (S (V "y") (V "z")))            == False
esTermino (S (V "x") (P (V "y") (V "z")))            == False
  • (esNormal a) se verifica si a está en forma normal. Por ejemplo,
esNormal (V "x")                                     == True
esNormal (P (V "x") (P (V "y") (V "z")))             == True
esNormal (S (V "x") (P (V "y") (V "z")))             == True
esNormal (P (V "x") (S (V "y") (V "z")))             == False
esNormal (P (S (V "x") (V "y")) (S (V "y") (V "z"))) == False

Nota: Puedes consultar las soluciones aquí.

Actualización de «Acrónimos»

He actualizado las soluciones del ejercicio Acrónimos cuyo enunciado es


A partir de una palabra de puede formar un acrónimo uniendo un prefijo de la primera con un sufijo de la segunda. Por ejemplo,

  • "ofimática" es un acrónimo de "oficina" e "informática"
  • "informática" es un acrónimo de "información" y "automática"
  • "teleñeco" es un acrónimo de "televisión" y "muñeco"

Definir la función

esAcronimo :: String -> String -> String -> Bool

tal que (esAcronimo xs ys zs) se verifica si xs es un acrónimo de ys y zs. Por ejemplo,

esAcronimo "ofimatica" "oficina" "informatica"       ==  True
esAcronimo "informatica" "informacion" "automatica"  ==  True

Nota: Puedes consultar las soluciones aquí.

Actualización de «Particiones de longitud fija»

He actualizado las soluciones del ejercicio Particiones de longitud fija cuyo enunciado es


Definir la función

particionesFijas :: Int -> Int -> [[Int]]

tal que (particionesFijas n k) es la lista de listas de k números enteros positivos no crecientes cuya suma es el número entero positivo n. Por ejemplo,

λ> particionesFijas 8 2
[[4,4],[5,3],[6,2],[7,1]]
λ> particionesFijas 8 3
[[3,3,2],[4,2,2],[4,3,1],[5,2,1],[6,1,1]]
λ> particionesFijas 9 3
[[3,3,3],[4,3,2],[4,4,1],[5,2,2],[5,3,1],[6,2,1],[7,1,1]]
λ> length (particionesFijas 67 5)
8056

Nota: Puedes consultar las soluciones aquí.

Actualización de «Evaluación de árboles de expresiones aritméticas»

He actualizado las soluciones del ejercicio Evaluación de árboles de expresiones aritméticas cuyo enunciado es


Las expresiones aritméticas se pueden representar como árboles con números en las hojas y operaciones en los nodos. Por ejemplo, la expresión 9-2*4 se puede representar por el árbol

  -
 / \
9   *
   / \
  2   4

Definiendo el tipo de dato Arbol por

data Arbol = H Int | N (Int -> Int -> Int) Arbol Arbol

la representación del árbol anterior es

N (-) (H 9) (N (*) (H 2) (H 4))

Definir la función

valor :: Arbol -> Int

tal que (valor a) es el valor de la expresión aritmética correspondiente al árbol a. Por ejemplo,

valor (N (-) (H 9) (N (*) (H 2) (H 4)))  ==  1
valor (N (+) (H 9) (N (*) (H 2) (H 4)))  ==  17
valor (N (+) (H 9) (N div (H 4) (H 2)))  ==  11
valor (N (+) (H 9) (N max (H 4) (H 2)))  ==  13

Nota: Puedes consultar las soluciones aquí.

Actualización de «Aplicaciones alternativas»

He actualizado las soluciones del ejercicio Aplicaciones alternativas cuyo enunciado es


Definir la función

alternativa :: (a -> b) -> (a -> b) -> [a] -> [b]

tal que (alternativa f g xs) es la lista obtenida aplicando alternativamente las funciones f y g a los elementos de xs. Por ejemplo,

alternativa (+1)  (+10) [1,2,3,4]    ==  [2,12,4,14]
alternativa (+10) (*10) [1,2,3,4,5]  ==  [11,20,13,40,15]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Repetición cíclica»

He actualizado las soluciones del ejercicio Repetición cíclica cuyo enunciado es


Definir la función

ciclica :: [a] -> [a]

tal que (ciclica xs) es la lista obtenida repitiendo cíclicamente los elementos de la lista no vacía xs. Por ejemplo,

take 10 (ciclica [3,5])    ==  [3,5,3,5,3,5,3,5,3,5]
take 10 (ciclica [3,5,7])  ==  [3,5,7,3,5,7,3,5,7,3]
take 10 (ciclica [3,5..])  ==  [3,5,7,9,11,13,15,17,19,21]

Nota: Puedes consultar las soluciones aquí.

Actualización de «Elemento común en menor posición»

He actualizado las soluciones del ejercicio Elemento común en menor posición cuyo enunciado es


Definir la función

elemento :: Eq a => [a] -> [a] -> [a]

tal que (elemento xs ys) es la lista formada por el elemento común a xs e ys con la menor posición global (considerando su posición en ambas listas). Por ejemplo.

elemento [3,7,6,9,8,0] [5,4,2,7,8,6,9]  ==  [7]
elemento [3,7,6,9] [9,5,6]              ==  [9]
elemento [5,3,6] [7,6,3]                ==  [3]
elemento [0,1,3] [3,1]                  ==  [3]
elemento [0,3,2] [1,2,3]                ==  [3]
elemento [3,7,6,3,8,0] [5,4,9,1,4,2,1]  ==  []
elemento [2,3,5] [7,4]                  ==  []

Nota: Como se observa en el 3ª ejemplo, en el caso de que un elemento x de xs pertenezca a ys y el elemento de ys en la misma posición que x pertenezca a xs, se elige como el de menor posición el de xs.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Cuantificadores sobre listas»

He actualizado las soluciones del ejercicio Cuantificadores sobre listas cuyo enunciado es


Definir la función

verificaP :: (a -> Bool) -> [[a]] -> Bool

tal que (verificaP p xs) se verifica si cada elemento de la lista xss contiene algún elemento que cumple el predicado p. Por ejemplo,

verificaP odd [[1,3,4,2], [4,5], [9]] == True
verificaP odd [[1,3,4,2], [4,8], [9]] == False

Nota: Puedes consultar las soluciones aquí.

Actualización de «Inversa a trozos»

He actualizado las soluciones del ejercicio Inversa a trozos cuyo enunciado es


Definir la función

inversa :: Int -> [a] -> [a]

tal que (inversa k xs) es la lista obtenida invirtiendo elementos de xs, k elementos cada vez. Si el número de elementos de xs no es un múltiplo de k, entonces los finales elementos de xs se dejen sin invertir. Por ejemplo,

inversa 3 [1..11]  ==  [3,2,1,6,5,4,9,8,7,10,11]
inversa 4 [1..11]  ==  [4,3,2,1,8,7,6,5,9,10,11]

Comprobar con QuickCheck que la función inversa es involutiva; es decir, para todo número k > 0 y toda lista xs, se tiene que (inversa k (inversa k xs)) es igual a xs.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Mínimos locales»

He actualizado las soluciones del ejercicio Mínimos locales cuyo enunciado es


Un mínimo local de una lista es un elemento de la lista que es menor que su predecesor y que su sucesor en la lista. Por ejemplo, 1 es un mínimo local de [3,2,1,3,7,7,1,0,2] ya que es menor que 2 (su predecesor) y que 3 (su sucesor).

Definir la función

minimosLocales :: Ord a => [a] -> [a]

tal que (minimosLocales xs) es la lista de los mínimos locales de la lista xs. Por ejemplo,

minimosLocales [3,2,1,3,7,7,9,6,8]  ==  [1,6]
minimosLocales [1..100]             ==  []
minimosLocales "mqexvzat"           ==  "eva"

Nota: Puedes consultar las soluciones aquí.

Actualización de «Pequeño test de inteligencia»

He actualizado las soluciones del ejercicio Pequeño test de inteligencia cuyo enunciado es


Recientemente se publicó en la Red un pequeño test de inteligencia cuyo objetivo consistía en descubrir una función a partir de una colección de ejemplos. Los ejemplos eran los siguientes

f 6  4 == 210
f 9  2 == 711
f 8  5 == 313
f 5  2 == 37
f 7  6 == 113
f 9  8 == 117
f 10 6 == 416
f 15 3 == 1218

Definir la función

f :: Int -> Int -> Int

tal que f cubra los ejemplos anteriores y la definición de f sea lo más corta posible (en número de palabras).


Nota: Puedes consultar las soluciones aquí.

Actualización de «Mayores elementos de una matriz»

He actualizado las soluciones del ejercicio Mayores elementos de una matriz cuyo enunciado es


Las matrices se pueden representar mediante listas de listas. Por ejemplo, la matriz

|3 2 5|
|4 9 7|

se puede representar por [[3,2,5],[4,9,7]].

Definir la función

mayores :: Ord a => Int -> [[a]] -> [(a,Int)]

tal que (mayores n xss) es la lista de los n mayores elementos de la matriz xss junto con sus correspondientes número de fila. Por ejemplo,

λ> mayores 4 [[4,26,9],[2,37,53],[41,1,8]]
[(53,2),(41,3),(37,2),(26,1)]

Comprobar con QuickCheck que todos los elementos de (mayores n xss) son mayores o iguales que los restantes elementos de xss.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Último dígito no nulo del factorial»

He actualizado las soluciones del ejercicio Último dígito no nulo del factorial cuyo enunciado es


El factorial de 7 es

7! = 1 * 2 * 3 * 4 * 5 * 6 * 7 = 5040

por tanto, el último dígito no nulo del factorial de 7 es 4.

Definir la función

ultimoNoNuloFactorial :: Integer -> Integer

tal que (ultimoNoNuloFactorial n) es el último dígito no nulo del factorial de n. Por ejemplo,

ultimoNoNuloFactorial  7  == 4
ultimoNoNuloFactorial 10  == 8
ultimoNoNuloFactorial 12  == 6
ultimoNoNuloFactorial 97  == 2
ultimoNoNuloFactorial  0  == 1

Comprobar con QuickCheck que si n es mayor que 4, entonces el último dígito no nulo del factorial de n es par.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Repetición de elementos»

He actualizado las soluciones del ejercicio Repetición de elementos cuyo enunciado es


Definir la función

repiteElementos :: Int -> [a] -> [a]

tal que (repiteElementos k xs) es la lista obtenida repitiendo k veces cada elemento de xs. Por ejemplo,

repiteElementos 3 [5,2,7,4]  ==  [5,5,5,2,2,2,7,7,7,4,4,4]

Comprobar con QuickCheck que, para todo número natural k y toda lista xs, el número de elementos de (repiteElementos k xs) es k veces el número de elementos de xs.


Nota: Puedes consultar las soluciones aquí.

Actualización de «Conjunto de primos relativos»

He actualizado las soluciones del ejercicio Conjunto de primos relativos cuyo enunciado es


Dos números enteros son primos relativos si no tienen ningún factor primo en común, o, dicho de otra manera, si no tienen otro divisor común más que 1 y -1. Equivalentemente son primos entre sí, si y sólo si, su máximo común divisor es igual a 1.

Por ejemplo, 6 y 35 son primos entre sí, pero 6 y 27 no lo son porque ambos son divisibles por 3

Definir la función

primosRelativos :: [Int] -> Bool

tal que (primosRelativos xs) se verifica si los elementos de xs son primos relativos dos a dos. Por ejemplo,

primosRelativos [6,35]         ==  True
primosRelativos [6,27]         ==  False
primosRelativos [2,3,4]        ==  False
primosRelativos [6,35,11]      ==  True
primosRelativos [6,35,11,221]  ==  True
primosRelativos [6,35,11,231]  ==  False

Nota: Puedes consultar las soluciones aquí.

Actualización de «Precio total»

He actualizado las soluciones del ejercicio Precio total cuyo enunciado es


Una función de precio determina el precio de cada elemento; por ejemplo,

precioCI :: String -> Int
precioCI "leche"       = 10
precioCI "mantequilla" = 18
precioCI "patatas"     = 22
precioCI "chocolate"   = 16

Definir la función

precioTotal :: (String -> Int) -> [String] -> Int

tal que (precioTotal f xs) es el precio total de los elementos de xs respecto de la función de precio f. Por ejemplo,

precioTotal precioCI ["leche", "leche", "mantequilla"]  ==  38
precioTotal precioCI ["chocolate", "mantequilla"]       ==  34

Nota: Puedes consultar las soluciones aquí.

Actualización de «Extensión de un fichero»

He actualizado las soluciones del ejercicio Extensión de un fichero cuyo enunciado es


La extensión de un fichero es la palabra a continuación del último punto en el nombre del fichero. Por ejemplo, la extensión de "documento.txt" es "txt"

Definir la función

extension :: String -> String

tal que (extension cs) es la extensión del fichero cs. Por ejemplo,

extension "ejercicio.hs"       ==  "hs"
extension "documento.txt"      ==  "txt"
extension "documento.txt.pdf"  ==  "pdf"
extension "resumen"            ==  ""

Nota: Puedes consultar las soluciones aquí.

Actualización de «Distancia de Hamming»

He actualizado las soluciones del ejercicio Distancia de Hamming cuyo enunciado es


La distancia de Hamming entre dos listas es el número de posiciones en que los correspondientes elementos son distintos. Por ejemplo, la distancia de Hamming entre "roma" y "loba" es 2 (porque hay 2 posiciones en las que los elementos correspondientes son distintos: la 1ª y la 3ª).

Definir la función

distancia :: Eq a => [a] -> [a] -> Int

tal que (distancia xs ys) es la distancia de Hamming entre xs e ys. Por ejemplo,

distancia "romano" "comino"  ==  2
distancia "romano" "camino"  ==  3
distancia "roma"   "comino"  ==  2
distancia "roma"   "camino"  ==  3
distancia "romano" "ron"     ==  1
distancia "romano" "cama"    ==  2
distancia "romano" "rama"    ==  1

Comprobar con QuickCheck si la distancia de Hamming tiene la siguiente propiedad

distancia(xs,ys) = 0 si, y sólo si, xs = ys

y, en el caso de que no se verifique, modificar ligeramente propiedad para obtener una condición necesaria y suficiente de distancia(xs,ys) = 0.


Actualización de «Suma de todos los anteriores»

He actualizado las soluciones del ejercicio Suma de todos los anteriores cuyo enunciado es


Definir la función

sumaAnteriores :: [Integer] -> Bool

tal que (sumaAnteriores xs) se verifica si cada elemento de la lista xs (excepto el primero) es la suma de sus anteriores elementos en la lista. Por ejemplo,

sumaAnteriores [3,3,6,12]  ==  True
sumaAnteriores [3,3,7,10]  ==  False
sumaAnteriores [3]         ==  True
sumaAnteriores []          ==  True

Actualización de «Máximo de una función»

He actualizado las soluciones del ejercicio Máximo de una función cuyo enunciado es


Se considera la siguiente función

g :: Integer -> Integer
g n = if n < 10 then n*n else n

Definir la función

max_g :: Integer -> Integer

tal que (max_g n) es el punto i del intervalo [0,n] donde g alcanza el máximo de sus valores, si n es positivo y 0 en caso contrario. Por ejemplo,

max_g (-7)  ==  0
max_g 7  ==  7
max_g 14  ==  9
max_g 84  ==  84

Comprobar con QuickCheck que la función max_g es equivalente a la función f definida por

f :: Integer -> Integer
f n | n < 0             = 0
    | n >= 10 && n < 81 = 9
    | otherwise         = n

Actualización de «Parte impar de un número»

He actualizado las soluciones del ejercicio Parte impar de un número cuyo enunciado es


Todo número entero \(n\) se puede escribir como \(m \times 2^k\), con \(m\) impar. Se dice que \(m\) es la parte impar de \(n\). Por ejemplo, la parte impar de 40 es 5 porque 40 = \(5 \times 2^3\).

Definir la función

parteImpar :: Int -> Int

tal que (parteImpar n) es la parte impar de n. Por ejemplo,

parteImpar 40  ==  5

Actualización de «Listas equidigitales»

He actualizado las soluciones del ejercicio Listas equidigitales cuyo enunciado es


Una lista de números naturales es equidigital si todos sus elementos tienen el mismo número de dígitos.

Definir la función

equidigital :: [Int] -> Bool

tal que (equidigital xs) se verifica si xs es una lista equidigital. Por ejemplo,

equidigital [343,225,777,943]   ==  True
equidigital [343,225,777,94,3]  ==  False

Actualización de «Divisibles por el primero»

He actualizado las soluciones del ejercicio Divisibles por el primero cuyo enunciado es


Definir la función

divisiblesPorPrimero :: [Int] -> Bool

tal que (divisibles xs) se verifica si todos los elementos positivos de xs son divisibles por el primero. Por ejemplo,

divisiblesPorPrimero [2,6,-3,0,18,-17,10]  ==  True
divisiblesPorPrimero [-13]                 ==  True
divisiblesPorPrimero [-3,6,1,-3,9,18]      ==  False
divisiblesPorPrimero [5,-2,-6,3]           ==  False
divisiblesPorPrimero []                    ==  True
divisiblesPorPrimero [0,2,4]               ==  False
divisiblesPorPrimero [0,-2,-4]             ==  True

Actualización de ejercicios del curso 2014-15

Con la próxima entrada se inicia la actualización de los ejercicios del curso 2014-15.

¿En qué consiste la actualización?

Cada ejercicio será mejorado mediante las siguientes acciones:

  • Ampliación de soluciones: se incorporarán nuevos enfoques y alternativas para resolver cada problema.
  • Integración en Stack: se integrarán los ejercicios en el proyecto Stack disponible en el repositorio Exercitium.
  • Comprobaciones con Hspec: se añadirán tests automatizados para validar las soluciones.
  • Verificación con QuickCheck: se comprobará la equivalencia entre las distintas soluciones propuestas
  • Análisis de eficiencia: se comparará el rendimiento de cada solución.

Estructura del curso

Los ejercicios están diseñados para incorporar conceptos de forma progresiva, siguiendo el desarrollo natural del curso. El material completo (temas, apuntes, ejercicios y exámenes) se encuentra disponible en Informática (2014-15).

Actualización de «Laberinto numérico»

He actualizado las soluciones del ejercicio Laberinto numérico cuyo enunciado es


El problema del laberinto numérico consiste en, dados un par de números, encontrar la longitud del camino más corto entre ellos usando sólo las siguientes operaciones:

  • multiplicar por 2,
  • dividir por 2 (sólo para los pares) y
  • sumar 2.

Por ejemplo, un camino mínimo

  • de 3 a 12 es [3,6,12],
  • de 12 a 3 es [12,6,3],
  • de 9 a 2 es [9,18,20,10,12,6,8,4,2] y
  • de 2 a 9 es [2,4,8,16,18,9].

Definir la función

longitudCaminoMinimo :: Int -> Int -> Int

tal que (longitudCaminoMinimo x y) es la longitud del camino mínimo desde x hasta y en el laberinto numérico.

longitudCaminoMinimo 3 12  ==  2
longitudCaminoMinimo 12 3  ==  2
longitudCaminoMinimo 9 2   ==  8
longitudCaminoMinimo 2 9   ==  5

Actualización de «Sustitución en una expresión aritmética»

He actualizado las soluciones del ejercicio Sustitución en una expresión aritmética cuyo enunciado es


La expresiones aritméticas se pueden representar mediante el siguiente tipo

data Expr = C Int
          | V Char
          | S Expr Expr
          | P Expr Expr
  deriving (Eq, Show)

por ejemplo, la expresión "z*(3+x)" se representa por (P (V 'z') (S (C 3) (V 'x'))).

Definir la función

sustitucion :: Expr -> [(Char, Int)] -> Expr

tal que (sustitucion e s) es la expresión obtenida sustituyendo las variables de la expresión e según se indica en la sustitución s. Por ejemplo,

λ> sustitucion (P (V 'z') (S (C 3) (V 'x'))) [('x',7),('z',9)]
P (C 9) (S (C 3) (C 7))
λ> sustitucion (P (V 'z') (S (C 3) (V 'y'))) [('x',7),('z',9)]
P (C 9) (S (C 3) (V 'y'))

Actualización de «Clausura de un conjunto respecto de una función»

He actualizado las soluciones del ejercicio Clausura de un conjunto respecto de una función cuyo enunciado es


Un conjunto A está cerrado respecto de una función f si para todo elemento x de A se tiene que f(x) pertenece a A. La clausura de un conjunto B respecto de una función f es el menor conjunto A que contiene a B y es cerrado respecto de f. Por ejemplo, la clausura de {0,1,2} respecto del opuesto es {0,1,2,-1,-2}.

Definir la función

clausura :: Eq a => (a -> a) -> [a] -> [a]

tal que (clausura f xs) es la clausura de xs respecto de f. Por ejemplo,

clausura (\x -> -x) [0,1,2]         ==  [0,1,2,-1,-2]
clausura (\x -> (x+1) `mod` 5) [0]  ==  [0,1,2,3,4]

Actualización de «Matriz permutación»

He actualizado las soluciones del ejercicio Matriz permutación cuyo enunciado es


Una matriz permutación es una matriz cuadrada con todos sus elementos iguales a 0, excepto uno cualquiera por cada fila y columna, el cual debe ser igual a 1.

En este ejercicio se usará el tipo de las matrices definido por

type Matriz a = Array (Int,Int) a

y los siguientes ejemplos de matrices

q1, q2, q3 :: Matriz Int
q1 = array ((1,1),(2,2)) [((1,1),1),((1,2),0),((2,1),0),((2,2),1)]
q2 = array ((1,1),(2,2)) [((1,1),0),((1,2),1),((2,1),0),((2,2),1)]
q3 = array ((1,1),(2,2)) [((1,1),3),((1,2),0),((2,1),0),((2,2),1)]

Definir la función

esMatrizPermutacion :: Num a => Matriz a -> Bool

tal que (esMatrizPermutacion p) se verifica si p es una matriz permutación. Por ejemplo.

esMatrizPermutacion q1  ==  True
esMatrizPermutacion q2  ==  False
esMatrizPermutacion q3  ==  False

Leer más…

Actualización de «Inserción en árboles binarios de búsqueda»

He actualizado las soluciones del ejercicio Inserción en árboles binarios de búsqueda cuyo enunciado es


Un árbol binario de búsqueda (ABB) es un árbol binario tal que el cada nodo es mayor que los valores de su subárbol izquierdo y menor que los valores de su subárbol derecho y, además, ambos subárboles son árboles binarios de búsqueda. Por ejemplo, al almacenar los valores de [8,4,2,6,3] en un ABB se puede obtener el siguiente ABB:

   3
  / \
 /   \
2     6
     / \
    4   8

Los ABB se pueden representar como tipo de dato algebraico:

data ABB = V
  | N Int ABB ABB
  deriving (Eq, Show)

Por ejemplo, la definición del ABB anteriore es

ej :: ABB
ej = N 3 (N 2 V V) (N 6 (N 4 V V) (N 8 V V))

Definir la función

inserta :: Int -> ABB -> ABB

tal que (inserta v a) es el árbol obtenido añadiendo el valor v al ABB a, si no es uno de sus valores. Por ejemplo,

λ>  inserta 5 ej
N 3 (N 2 V V) (N 6 (N 4 V (N 5 V V)) (N 8 V V))
λ>  inserta 1 ej
N 3 (N 2 (N 1 V V) V) (N 6 (N 4 V V) (N 8 V V))
λ>  inserta 2 ej
N 3 (N 2 V V) (N 6 (N 4 V V) (N 8 V V))

Comprobar con QuickCheck que al insertar un valor en un ABB se obtiene otro ABB.


Actualización de «Producto de matrices como listas de listas»

He actualizado las soluciones del ejercicio Producto de matrices como listas de listas cuyo enunciado es


Las matrices pueden representarse mediante una lista de listas donde cada una de las lista representa una fila de la matriz. Por ejemplo, la matriz

|1 0 -2|
|0 3 -1|

puede representarse por [[1,0,-2],[0,3,-1]].

Definir la función

producto :: Num a => [[a]] -> [[a]] -> [[a]]

tal que (producto p q) es el producto de las matrices p y q. Por ejemplo,

λ> producto [[1,0,-2],[0,3,-1]] [[0,3],[-2,-1],[0,4]]
[[0,-5],[-6,-7]]

Actualización de «Sucesiones pucelanas»

He actualizado las soluciones del ejercicio Sucesiones pucelanas cuyo enunciado es


En la Olimpiada de Matemática del 2010 se planteó el siguiente problema:

Una sucesión pucelana es una sucesión creciente de 16 números impares positivos consecutivos, cuya suma es un cubo perfecto. ¿Cuántas sucesiones pucelanas tienen solamente números de tres cifras?

Para resolverlo se propone el siguiente ejercicio.

Definir la función

pucelanasConNcifras :: Int -> [[Int]]

tal que (pucelanasConNcifras n) es la lista de las sucesiones pucelanas que tienen solamente números de n cifras. Por ejemplo,

λ> pucelanasConNcifras 2
[[17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47]]

Calcular cuántas sucesiones pucelanas tienen solamente números de tres cifras.


Actualización de «Todas tienen par»

He actualizado las soluciones del ejercicio Todas tienen par cuyo enunciado es


Definir la función

todasTienenPar :: [[Int]] -> Bool

tal que tal que todasTienenPar xss se verifica si cada elemento de la lista de listas xss contiene algún número par. Por ejemplo,

todasTienenPar [[1,2],[3,4,5],[8]]  ==  True
todasTienenPar [[1,2],[3,5]]        ==  False

Actualización de «Producto cartesiano de una familia de conjuntos»

He actualizado las soluciones del ejercicio Producto cartesiano de una familia de conjuntos cuyo enunciado es


Definir la función

producto :: [[a]] -> [[a]]

tal que (producto xss) es el producto cartesiano de los conjuntos xss. Por ejemplo,

λ> producto [[2,5],[6,4]]
[[2,6],[2,4],[5,6],[5,4]]
λ> producto [[1,3],[2,5],[6,4]]
[[1,2,6],[1,2,4],[1,5,6],[1,5,4],[3,2,6],[3,2,4],[3,5,6],[3,5,4]]
λ> producto [[1,3,5],[2,4]]
[[1,2],[1,4],[3,2],[3,4],[5,2],[5,4]]
λ> producto []
[[]]

Comprobar con QuickCheck que para toda lista de listas de enteros, xss, se verifica que el número de elementos de (producto xss) es igual al producto de los números de elementos de cada una de las listas de xss.


Actualización de «Código Morse»

He actualizado las soluciones del ejercicio Código Morse cuyo enunciado es


El código Morse es un sistema de representación de letras y números mediante señales emitidas de forma intermitente.

A los signos (letras mayúsculas o dígitos) se le asigna un código como se muestra a continuación

+---+-------+---+-------+---+-------+---+-------+
| A | .-    | J | .---  | S | ...   | 1 | ..--- |
| B | -...  | K | -.-   | T | -     | 2 | ...-- |
| C | -.-.  | L | .-..  | U | ..-   | 3 | ....- |
| D | -..   | M | --    | V | ...-  | 4 | ..... |
| E | .     | N | -.    | W | .--   | 5 | -.... |
| F | ..-.  | O | ---   | X | -..-  | 6 | --... |
| G | --.   | P | .--.  | Y | -.--  | 7 | ---.. |
| H | ....  | Q | --.-  | Z | --..  | 8 | ----. |
| I | ..    | R | .-.   | 0 | .---- | 9 | ----- |
+---+-------+---+-------+---+-------+---+-------+

El código Morse de las palabras se obtiene a partir del de sus caracteres insertando un espacio entre cada uno. Por ejemplo, el código de "todo" es "- --- -.. ---"

El código Morse de las frase se obtiene a partir del de sus palabras insertando un espacio entre cada uno. Por ejemplo, el código de "todo o nada" es "- --- -.. --- --- -. .- -.. .-"

Definir las funciones

fraseAmorse :: String -> String
morseAfrase :: String -> String

tales que

  • (fraseAmorse cs) es la traducción de la frase cs a Morse. Por ejemplo,
λ> fraseAmorse "En todo la medida"
". -.  - --- -.. ---  .-.. .-  -- . -.. .. -.. .-"
  • (morseAfrase cs) es la frase cuya traducción a Morse es cs. Por ejemplo,
λ> morseAfrase ". -.  - --- -.. ---  .-.. .-  -- . -.. .. -.. .-"
"EN TODO LA MEDIDA"

Nota: La lista de los códigos Morse de A, B, ..., Z, 0, 1, ..., 9 es

[".-","-...","-.-.","-..",".","..-.","--.","....","..",".---",
 "-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-",
 "..-","...-",".--","-..-","-.--","--..",".----","..---","...--",
 "....-",".....","-....","--...","---..","----.","-----"]

Actualización de «Elemento más cercano que cumple una propiedad»

He actualizado las soluciones del ejercicio Elemento más cercano que cumple una propiedad cuyo enunciado es


Definir la función

cercano :: (a -> Bool) -> Int -> [a] -> Maybe a

tal que (cercano p n xs) es el elemento de xs cuya posición es la cercana a la posición n que verifica la propiedad p. La búsqueda comienza en n y los elementos se analizan en el siguiente orden: n, n+1, n-1, n+2, n-2,... Por ejemplo,

cercano (`elem` "aeiou") 6 "Sevilla"     ==  Just 'a'
cercano (`elem` "aeiou") 1 "Sevilla"     ==  Just 'e'
cercano (`elem` "aeiou") 2 "Sevilla"     ==  Just 'i'
cercano (`elem` "aeiou") 5 "Sevilla"     ==  Just 'a'
cercano (`elem` "aeiou") 9 "Sevilla"     ==  Just 'a'
cercano (`elem` "aeiou") (-3) "Sevilla"  ==  Just 'e'
cercano (>100) 4 [200,1,150,2,4]         ==  Just 150
cercano even 5 [1,3..99]                 ==  Nothing

Actualización de «Representación de Zeckendorf»

He actualizado las soluciones del ejercicio Representación de Zeckendorf cuyo enunciado es


Los primeros números de Fibonacci son

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, ...

tales que los dos primeros son iguales a 1 y los siguientes se obtienen sumando los dos anteriores.

El teorema de Zeckendorf establece que todo entero positivo n se puede representar, de manera única, como la suma de números de Fibonacci no consecutivos decrecientes. Dicha suma se llama la representación de Zeckendorf de n. Por ejemplo, la representación de Zeckendorf de 100 es

100 = 89 + 8 + 3

Hay otras formas de representar 100 como sumas de números de Fibonacci; por ejemplo,

100 = 89 +  8 + 2 + 1
100 = 55 + 34 + 8 + 3

pero no son representaciones de Zeckendorf porque 1 y 2 son números de Fibonacci consecutivos, al igual que 34 y 55.

Definir la función

zeckendorf :: Integer -> [Integer]

tal que (zeckendorf n) es la representación de Zeckendorf de n. Por ejemplo,

zeckendorf 100       == [89,8,3]
zeckendorf 2014      == [1597,377,34,5,1]
zeckendorf 28656     == [17711,6765,2584,987,377,144,55,21,8,3,1]
zeckendorf 14930396  == [14930352,34,8,2]

Actualización de «Ventana deslizante»

He actualizado las soluciones del ejercicio Ventana deslizante cuyo enunciado es


Definir la función

ventanas :: Int -> Int -> [a] -> [[a]]

tal que (ventanas x y zs) es la lista de ventanas de zs de tamaño x y deslizamiento y; es decir, listas de x elementos consecutivos de zs (salvo, posiblemente, la última que puede ser menor) tales que la diferencia de posiciones entre los primeros elementos de ventanas consecutivas es y. Por ejemplo,

ventanas 3 2 [5,1,9,2] == [[5,1,9],[9,2]]
ventanas 3 3 [5,1,9,2] == [[5,1,9],[2]]
ventanas 3 4 [5,1,9,2] == [[5,1,9]]
ventanas 4 1 [1..7]    == [[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]
ventanas 4 2 [1..7]    == [[1,2,3,4],[3,4,5,6],[5,6,7]]
ventanas 4 3 [1..7]    == [[1,2,3,4],[4,5,6,7]]
ventanas 4 4 [1..7]    == [[1,2,3,4],[5,6,7]]
ventanas 4 5 [1..7]    == [[1,2,3,4],[6,7]]
ventanas 4 6 [1..7]    == [[1,2,3,4],[7]]
ventanas 4 7 [1..7]    == [[1,2,3,4]]
ventanas 4 8 [1..7]    == [[1,2,3,4]]
ventanas 3 2 "abcdef"  == ["abc","cde","ef"]
ventanas 3 3 "abcdef"  == ["abc","def"]
ventanas 3 4 "abcdef"  == ["abc","ef"]
ventanas 3 5 "abcdef"  == ["abc","f"]
ventanas 3 6 "abcdef"  == ["abc"]
ventanas 3 7 "abcdef"  == ["abc"]
ventanas 1 5 "abcdef"  == ["a","f"]

Actualización de «Divide si todos son múltiplos»

He actualizado las soluciones del ejercicio Divide si todos son múltiplos cuyo enunciado es


Definir la función

divideSiTodosMultiplos :: Integral a => a -> [a] -> Maybe [a]

tal que (divideSiTodosMultiplos x ys) es justo la lista de los cocientes de los elementos de ys entre x si todos son múltiplos de de número no nulo x y Nothing en caso contrario. Por ejemplo,

divideSiTodosMultiplos 2 [6,10,4]  ==  Just [3,5,2]
divideSiTodosMultiplos 2 [6,10,5]  ==  Nothing

Actualización de «Renombramiento de un árbol»

He actualizado las soluciones del ejercicio Renombramiento de un árbol cuyo enunciado es


Los árboles binarios se pueden representar mediante el tipo Arbol definido por

data Arbol a = H a
             | N a (Arbol a) (Arbol a)
  deriving (Show, Eq, Foldable, Functor)

Por ejemplo, el árbol

      "C"
      / \
     /   \
    /     \
  "B"     "A"
  / \     / \
"A" "B" "B" "C"

se puede definir por

ej1 :: Arbol String
ej1 = N "C" (N "B" (H "A") (H "B")) (N "A" (H "B") (H "C"))

Definir la función

renombraArbol :: Arbol t -> Arbol Int

tal que (renombraArbol a) es el árbol obtenido sustituyendo el valor de los nodos y hojas por números tales que tengan el mismo valor si y sólo si coincide su contenido. Por ejemplo,

λ> renombraArbol ej1
N 2 (N 1 (H 0) (H 1)) (N 0 (H 1) (H 2))

Gráficamente,

      2
     / \
    /   \
   /     \
  1       0
 / \     / \
0   1   1   2

Actualización de «Límite de sucesiones»

He actualizado las soluciones del ejercicio Límite de sucesiones cuyo enunciado es


Definir la función

limite :: (Double -> Double) -> Double -> Double

tal que (limite f a) es el valor de f en el primer término x tal que, para todo y entre x+1 y x+100, el valor absoluto de la diferencia entre f(y) y f(x) es menor que a. Por ejemplo,

limite (\n -> (2*n+1)/(n+5)) 0.001  ==  1.9900110987791344
limite (\n -> (1+1/n)**n) 0.001     ==  2.714072874546881

Actualización de «Eliminación de n elementos»

He actualizado las soluciones del ejercicio Eliminación de n elementos cuyo enunciado es


Definir la función

elimina :: Int -> [a] -> [[a]]

tal que (elimina n xs) es la lista de las listas obtenidas eliminando n elementos de xs. Por ejemplo,

elimina 0 "abcd"  ==  ["abcd"]
elimina 1 "abcd"  ==  ["bcd","acd","abd","abc"]
elimina 2 "abcd"  ==  ["cd","bd","bc","ad","ac","ab"]
elimina 3 "abcd"  ==  ["d","c","b","a"]
elimina 4 "abcd"  ==  [""]
elimina 5 "abcd"  ==  []
elimina 6 "abcd"  ==  []

Actualización de «Intercalación de n copias»

He actualizado las soluciones del ejercicio Intercalación de n copias cuyo enunciado es


Definir la función

intercala :: Int -> a -> [a] -> [[a]]

tal que (intercala n x ys) es la lista de la listas obtenidas intercalando n copias de x en ys. Por ejemplo,

intercala 2 'a' "bc" == ["bcaa","baca","baac","abca","abac","aabc"]
intercala 2 'a' "c"  == ["caa","aca","aac"]
intercala 1 'a' "c"  == ["ca","ac"]
intercala 0 'a' "c"  == ["c"]

Actualización de «Sopa de letras»

He actualizado las soluciones del ejercicio Sopa de letras cuyo enunciado es


Las matrices se puede representar mediante tablas cuyos índices son pares de números naturales:

type Matriz a = Array (Int,Int) a

Definir la función

enLaSopa :: Eq a => [a] -> Matriz a -> Bool

tal que (enLaSopa c p) se verifica si c está en la matriz p en horizontal o en vertical. Por ejemplo, si ej1 es la matriz siguiente:

ej1 :: Matriz Char
ej1 = listaMatriz ["mjtholueq",
                   "juhoolauh",
                   "dariouhyj",
                   "rngkploaa"]

donde la función listaMatriz está definida por

listaMatriz :: [[a]] -> Matriz a
listaMatriz xss = listArray ((1,1),(m,n)) (concat xss)
  where m = length xss
        n = length (head xss)

entonces,

enLaSopa "dar"  p  ==  True   -- En horizontal a la derecha en la 3ª fila
enLaSopa "oir"  p  ==  True   -- En horizontal a la izquierda en la 3ª fila
enLaSopa "juan" p  ==  True   -- En vertical descendente en la 2ª columna
enLaSopa "kio"  p  ==  True   -- En vertical ascendente en la 3ª columna
enLaSopa "Juan" p  ==  False
enLaSopa "hola" p  ==  False

Actualización de «N gramas»

He actualizado las soluciones del ejercicio N gramas cuyo enunciado es


Un n-grama de una sucesión es una subsucesión contigua de n elementos.

Definir la función

nGramas :: Int -> [a] -> [[a]]

tal que (nGramas k xs) es la lista de los n-gramas de xs de longitud k. Por ejemplo,

nGramas 0 "abcd"  ==  []
nGramas 1 "abcd"  ==  ["a","b","c","d"]
nGramas 2 "abcd"  ==  ["ab", "bc", "cd"]
nGramas 3 "abcd"  ==  ["abc", "bcd"]
nGramas 4 "abcd"  ==  ["abcd"]
nGramas 5 "abcd"  ==  []

Actualización de «Entero positivo de la cadena»

He actualizado las soluciones del ejercicio Entero positivo de la cadena cuyo enunciado es


Definir la función

enteroPositivo :: String -> Maybe Int

tal que (enteroPositivo cs) es justo el contenido de la cadena cs, si dicho contenido es un entero positivo, y Nothing en caso contrario. Por ejemplo,

enteroPositivo "235"    ==  Just 235
enteroPositivo "-235"   ==  Nothing
enteroPositivo "23.5"   ==  Nothing
enteroPositivo "235 "   ==  Nothing
enteroPositivo "cinco"  ==  Nothing
enteroPositivo ""       ==  Nothing

Actualización de «Filtro booleano»

He actualizado las soluciones del ejercicio Filtro booleano cuyo enunciado es


Definir la función

filtroBooleano :: [Bool] -> [a] -> [Maybe a]

tal que (filtroBooleano xs ys) es la lista de los elementos de ys tales que el elemento de xs en la misma posición es verdadero. Por ejemplo,

λ> filtroBooleano [True,False,True] "Sevilla"
[Just 'S',Nothing,Just 'v']
λ> filtroBooleano (repeat True) "abc"
[Just 'a',Just 'b',Just 'c']
λ> take 3 (filtroBooleano (repeat True) [1..])
[Just 1,Just 2,Just 3]
λ> take 3 (filtroBooleano (repeat False) [1..])
[Nothing,Nothing,Nothing]
λ> take 3 (filtroBooleano (cycle [True,False]) [1..])
[Just 1,Nothing,Just 3]

Actualización de «Mayor sucesión del problema 3n+1»

He actualizado las soluciones del ejercicio Mayor sucesión del problema 3n+1 cuyo enunciado es


La sucesión 3n+1 generada por un número entero positivo x es sucesión generada por el siguiente algoritmo: Se empieza con el número x. Si x es par, se divide entre 2. Si x es impar, se multiplica por 3 y se le suma 1. El proceso se repite con el número obtenido hasta que se alcanza el valor 1. Por ejemplo, la sucesión de números generadas cuando se empieza en 22 es

22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1

Se ha conjeturado (aunque no demostrado) que este algoritmo siempre alcanza el 1 empezando en cualquier entero positivo.

Definir la función

mayorLongitud :: Integer -> Integer -> Integer

tal que (mayorLongitud i j) es el máximo de las longitudes de las sucesiones 3n+1 para todos los números comprendidos entre i y j, ambos inclusives. Por ejemplo,

mayorLongitud   1   10  ==  20
mayorLongitud 100  200  ==  125
mayorLongitud 201  210  ==  89
mayorLongitud 900 1000  ==  174

Actualización de «Buscaminas»

He actualizado las soluciones del ejercicio Buscaminas cuyo enunciado es


El buscaminas es un juego cuyo objetivo es despejar un campo de minas sin detonar ninguna.

El campo de minas se representa mediante un cuadrado con NxN casillas. Algunas casillas tienen un número, este número indica las minas que hay en todas las casillas vecinas. Cada casilla tiene como máximo 8 vecinas. Por ejemplo, el campo 4x4 de la izquierda contiene dos minas, cada una representada por el número 9, y a la derecha se muestra el campo obtenido anotando las minas vecinas de cada casilla

9 0 0 0       9 1 0 0
0 0 0 0       2 2 1 0
0 9 0 0       1 9 1 0
0 0 0 0       1 1 1 0

de la misma forma, la anotación del siguiente a la izquierda es el de la derecha

9 9 0 0 0     9 9 1 0 0
0 0 0 0 0     3 3 2 0 0
0 9 0 0 0     1 9 1 0 0

Utilizando la librería Data.Matrix, los campos de minas se representan mediante matrices:

type Campo = Matrix Int

Por ejemplo, los anteriores campos de la izquierda se definen por

ejCampo1, ejCampo2 :: Campo
ejCampo1 = fromLists [[9,0,0,0],
                      [0,0,0,0],
                      [0,9,0,0],
                      [0,0,0,0]]
ejCampo2 = fromLists [[9,9,0,0,0],
                      [0,0,0,0,0],
                      [0,9,0,0,0]]

Definir la función

buscaminas :: Campo -> Campo

tal que buscaminas c es el campo obtenido anotando las minas vecinas de cada casilla. Por ejemplo,

λ> buscaminas ejCampo1
( 9 1 0 0 )
( 2 2 1 0 )
( 1 9 1 0 )
( 1 1 1 0 )

λ> buscaminas ejCampo2
( 9 9 1 0 0 )
( 3 3 2 0 0 )
( 1 9 1 0 0 )

Actualización de «Selección hasta el primero que falla inclusive»

He actualizado las soluciones del ejercicio Selección hasta el primero que falla inclusive cuyo enunciado es


Definir la función

seleccionConFallo :: (a -> Bool) -> [a] -> [a]

tal que (seleccionConFallo p xs) es la lista de los elementos de xs que cumplen el predicado p hasta el primero que no lo cumple inclusive. Por ejemplo,

seleccionConFallo (<5) [3,2,5,7,1,0]  ==  [3,2,5]
seleccionConFallo odd [1..4]          ==  [1,2]
seleccionConFallo odd [1,3,5]         ==  [1,3,5]
seleccionConFallo (<5) [10..20]       ==  [10]

Actualización de «Descomposiciones como sumas de n sumandos»

He actualizado las soluciones del ejercicio Descomposiciones como sumas de n sumandos cuyo enunciado es


Definir la función

sumas :: (Num a, Ord a) => Int -> [a] -> a -> [[a]]

tal que (sumas n ys x) es la lista de las descomposiciones de x como sumas de n sumandos en la lista ys. Por ejemplo,

sumas 2 [1,2] 3     == [[1,2]]
sumas 2 [-1] (-2)   == [[-1,-1]]
sumas 2 [-1,3,-1] 2 == [[-1,3]]
sumas 2 [1,2] 4     == [[2,2]]
sumas 2 [1,2] 5     == []
sumas 3 [1,2] 5     == [[1,2,2]]
sumas 3 [1,2] 6     == [[2,2,2]]
sumas 2 [1,2,5] 6   == [[1,5]]
sumas 2 [1,2,3,5] 4 == [[1,3],[2,2]]
sumas 2 [1..5] 6    == [[1,5],[2,4],[3,3]]
sumas 3 [1..5] 7    == [[1,1,5],[1,2,4],[1,3,3],[2,2,3]]
sumas 3 [1..200] 4  == [[1,1,2]]

Actualización de «Órbita prima»

He actualizado las soluciones del ejercicio Órbita prima cuyo enunciado es


La órbita prima de un número n es la sucesión construida de la siguiente forma:

  • si n es compuesto su órbita no tiene elementos
  • si n es primo, entonces n está en su órbita; además, sumamos n y sus dígitos, si el resultado es un número primo repetimos el proceso hasta obtener un número compuesto.

Por ejemplo, con el 11 podemos repetir el proceso dos veces

13 = 11+1+1
17 = 13+1+3
25 = 17+1+7

Así, la órbita prima de 11 es 11, 13, 17.

Definir la función

orbita :: Integer -> [Integer]

tal que (orbita n) es la órbita prima de n. Por ejemplo,

orbita 11 == [11,13,17]
orbita 59 == [59,73,83]

Calcular el menor número cuya órbita prima tiene más de 3 elementos.


Actualización de «Ordenada cíclicamente»

He actualizado las soluciones del ejercicio Ordenada cíclicamente cuyo enunciado es


Se dice que una sucesión x(1), ..., x(n) está ordenada cíclicamente si existe un índice i tal que la sucesión

x(i), x(i+1), ..., x(n), x(1), ..., x(i-1)

está ordenada creciente de forma estricta.

Definir la función

ordenadaCiclicamente :: Ord a => [a] -> Maybe Int

tal que (ordenadaCiclicamente xs) es el índice a partir del cual está ordenada, si la lista está ordenado cíclicamente y Nothing en caso contrario. Por ejemplo,

ordenadaCiclicamente [1,2,3,4]      ==  Just 0
ordenadaCiclicamente [5,8,1,3]      ==  Just 2
ordenadaCiclicamente [4,6,7,5,1,3]  ==  Nothing
ordenadaCiclicamente [1,0,3,2]      ==  Nothing
ordenadaCiclicamente [1,2,0]        ==  Just 2
ordenadaCiclicamente "cdeab"        ==  Just 3

Nota: Se supone que el argumento es una lista no vacía sin elementos repetidos.


Actualización de «Eliminación de las ocurrencias aisladas»

He actualizado las soluciones del ejercicio Eliminación de las ocurrencias aisladas cuyo enunciado es


Definir la función

eliminaAisladas :: Eq a => a -> [a] -> [a]

tal que (eliminaAisladas x ys) es la lista obtenida eliminando de ys las ocurrencias aisladas de x (es decir, aquellas ocurrencias de x tales que su elemento anterior y posterior son distintos de x). Por ejemplo,

eliminaAisladas 'X' ""                  == ""
eliminaAisladas 'X' "X"                 == ""
eliminaAisladas 'X' "XX"                == "XX"
eliminaAisladas 'X' "XXX"               == "XXX"
eliminaAisladas 'X' "abcd"              == "abcd"
eliminaAisladas 'X' "Xabcd"             == "abcd"
eliminaAisladas 'X' "XXabcd"            == "XXabcd"
eliminaAisladas 'X' "XXXabcd"           == "XXXabcd"
eliminaAisladas 'X' "abcdX"             == "abcd"
eliminaAisladas 'X' "abcdXX"            == "abcdXX"
eliminaAisladas 'X' "abcdXXX"           == "abcdXXX"
eliminaAisladas 'X' "abXcd"             == "abcd"
eliminaAisladas 'X' "abXXcd"            == "abXXcd"
eliminaAisladas 'X' "abXXXcd"           == "abXXXcd"
eliminaAisladas 'X' "XabXcdX"           == "abcd"
eliminaAisladas 'X' "XXabXXcdXX"        == "XXabXXcdXX"
eliminaAisladas 'X' "XXXabXXXcdXXX"     == "XXXabXXXcdXXX"
eliminaAisladas 'X' "XabXXcdXeXXXfXx"   == "abXXcdeXXXfx"

Actualización de «Emparejamiento de árboles»

He actualizado las soluciones del ejercicio Emparejamiento de árboles cuyo enunciado es


Los árboles se pueden representar mediante el siguiente tipo de datos

data Arbol a = N a [Arbol a]
  deriving (Show, Eq)

Por ejemplo, los árboles

  1               3
 / \             /|\
6   3           / | \
    |          5  4  7
    5          |     /\
               6    2  1

se representan por

ej1, ej2 :: Arbol Int
ej1 = N 1 [N 6 [],N 3 [N 5 []]]
ej2 = N 3 [N 5 [N 6 []], N 4 [], N 7 [N 2 [], N 1 []]]

Definir la función

emparejaArboles :: (a -> b -> c) -> Arbol a -> Arbol b -> Arbol c

tal que (emparejaArboles f a1 a2) es el árbol obtenido aplicando la función f a los elementos de los árboles a1 y a2 que se encuentran en la misma posición. Por ejemplo,

λ> emparejaArboles (+) (N 1 [N 2 [], N 3[]]) (N 1 [N 6 []])
N 2 [N 8 []]
λ> emparejaArboles (+) ej1 ej2
N 4 [N 11 [],N 7 []]
λ> emparejaArboles (+) ej1 ej1
N 2 [N 12 [],N 6 [N 10 []]]

Actualización de «Separación por posición»

He actualizado las soluciones del ejercicio Separación por posición cuyo enunciado es


Definir la función

particion :: [a] -> ([a],[a])

tal que (particion xs) es el par cuya primera componente son los elementos de xs en posiciones pares y su segunda componente son los restantes elementos. Por ejemplo,

particion [3,5,6,2]    ==  ([3,6],[5,2])
particion [3,5,6,2,7]  ==  ([3,6,7],[5,2])
particion "particion"  ==  ("priin","atco")

Actualización de «Número de inversiones»

He actualizado las soluciones del ejercicio Número de inversiones cuyo enunciado es


Se dice que en una sucesión de números x(1), x(2), ..., x(n) hay una inversión cuando existe un par de números x(i) > x(j), siendo i < j. Por ejemplo, en la permutación 2, 1, 4, 3 hay dos inversiones (2 antes que 1 y 4 antes que 3) y en la permutación 4, 3, 1, 2 hay cinco inversiones (4 antes 3, 4 antes 1, 4 antes 2, 3 antes 1, 3 antes 2).

Definir la función

numeroInversiones :: Ord a => [a] -> Int

tal que (numeroInversiones xs) es el número de inversiones de xs. Por ejemplo,

numeroInversiones [2,1,4,3]  ==  2
numeroInversiones [4,3,1,2]  ==  5

Actualización de «Descomposiciones triangulares»

He actualizado las soluciones del ejercicio Descomposiciones triangulares cuyo enunciado es


Los números triangulares se forman como sigue

*     *      *
     * *    * *
           * * *
1     3      6

La sucesión de los números triangulares se obtiene sumando los números naturales. Así, los 5 primeros números triangulares son

 1 = 1
 3 = 1 + 2
 6 = 1 + 2 + 3
10 = 1 + 2 + 3 + 4
15 = 1 + 2 + 3 + 4 + 5

Definir la función

descomposicionesTriangulares :: Int -> [(Int, Int, Int)]

tal que descomposicionesTriangulares n es la lista de las ternas correspondientes a las descomposiciones de n en tres sumandos, como máximo, formados por números triangulares. Por ejemplo,

λ> descomposicionesTriangulares 4
[]
λ> descomposicionesTriangulares 5
[(1,1,3)]
λ> descomposicionesTriangulares 12
[(1,1,10),(3,3,6)]
λ> descomposicionesTriangulares 30
[(1,1,28),(3,6,21),(10,10,10)]
λ> descomposicionesTriangulares 61
[(1,15,45),(3,3,55),(6,10,45),(10,15,36)]
λ> descomposicionesTriangulares 52
[(1,6,45),(1,15,36),(3,21,28),(6,10,36),(10,21,21)]
λ> descomposicionesTriangulares 82
[(1,3,78),(1,15,66),(1,36,45),(6,10,66),(6,21,55),(10,36,36)]
λ> length (descomposicionesTriangulares (5*10^6))
390

Actualización de «Índices de valores verdaderos»

He actualizado las soluciones del ejercicio Índices de valores verdaderos cuyo enunciado es


Definir la función

indicesVerdaderos :: [Int] -> [Bool]

tal que (indicesVerdaderos xs) es la lista infinita de booleanos tal que sólo son verdaderos los elementos cuyos índices pertenecen a la lista estrictamente creciente xs. Por ejemplo,

λ> take 6 (indicesVerdaderos [1,4])
[False,True,False,False,True,False]
λ> take 6 (indicesVerdaderos [0,2..])
[True,False,True,False,True,False]
λ> take 3 (indicesVerdaderos [])
[False,False,False]
λ> take 6 (indicesVerdaderos [1..])
[False,True,True,True,True,True]
λ> last (take (8*10^7) (indicesVerdaderos [0,5..]))
False

Actualización de «Código de las alergias»

He actualizado las soluciones del ejercicio Código de las alergias cuyo enunciado es


Para la determinación de las alergia se utiliza los siguientes códigos para los alérgenos:

Huevos ........   1
Cacahuetes ....   2
Mariscos ......   4
Fresas ........   8
Tomates .......  16
Chocolate .....  32
Polen .........  64
Gatos ......... 128

Así, si Juan es alérgico a los cacahuetes y al chocolate, su puntuación es 34 (es decir, 2+32).

Los alérgenos se representan mediante el siguiente tipo de dato

data Alergeno = Huevos
              | Cacahuetes
              | Mariscos
              | Fresas
              | Tomates
              | Chocolate
              | Polen
              | Gatos
  deriving (Enum, Eq, Show, Bounded)

Definir la función

alergias :: Int -> [Alergeno]

tal que (alergias n) es la lista de alergias correspondiente a una puntuación n. Por ejemplo,

λ> alergias 1
[Huevos]
λ> alergias 2
[Cacahuetes]
λ> alergias 3
[Huevos,Cacahuetes]
λ> alergias 5
[Huevos,Mariscos]
λ> alergias 255
[Huevos,Cacahuetes,Mariscos,Fresas,Tomates,Chocolate,Polen,Gatos]

Actualización de «Pim, Pam, Pum y divisibilidad»

He actualizado las soluciones del ejercicio Pim, Pam, Pum y divisibilidad cuyo enunciado es


Definir la función

sonido :: Int -> String

tal que (sonido n) escribe "Pim" si n es divisible por 3, además escribe "Pam" si n es divisible por 5 y también escribe "Pum" si n es divisible por 7. Por ejemplo,

sonido   3  ==  "Pim"
sonido   5  ==  "Pam"
sonido   7  ==  "Pum"
sonido   8  ==  ""
sonido   9  ==  "Pim"
sonido  15  ==  "PimPam"
sonido  21  ==  "PimPum"
sonido  35  ==  "PamPum"
sonido 105  ==  "PimPamPum"

Actualización de «Elementos de una matriz con algún vecino menor»

He actualizado las soluciones del ejercicio Elementos de una matriz con algún vecino menor cuyo enunciado es


Las matrices puede representarse mediante tablas cuyos índices son pares de números naturales. Su tipo se define por

type Matriz = Array (Int,Int) Int

Por ejemplo, la matriz

|9 4 6 5|
|8 1 7 3|
|4 2 5 4|

se define por

ej :: Matriz
ej = listArray ((1,1),(3,4)) [9,4,6,5,8,1,7,3,4,2,5,4]

Los vecinos de un elemento son los que están a un paso en la misma fila, columna o diagonal. Por ejemplo, en la matriz anterior, el 1 tiene 8 vecinos (el 9, 4, 6, 8, 7, 4, 2 y 5) pero el 9 sólo tiene 3 vecinos (el 4, 8 y 1).

Definir la función

algunoMenor :: Matriz -> [Int]

tal que (algunoMenor p) es la lista de los elementos de p que tienen algún vecino menor que él. Por ejemplo,

algunoMenor ej == [9,4,6,5,8,7,4,2,5,4]

pues sólo el 1 y el 3 no tienen ningún vecino menor en la matriz.


Actualización de «Enumeración de árboles binarios»

He actualizado las soluciones del ejercicio Enumeración de árboles binarios cuyo enunciado es


Los árboles binarios se pueden representar mediante el tipo Arbol definido por

data Arbol a = H a
             | N (Arbol a) a (Arbol a)
   deriving Show

Por ejemplo, el árbol

      "B"
      / \
     /   \
    /     \
  "B"     "A"
  / \     / \
"A" "B" "C" "C"

se puede definir por

ej1 :: Arbol String
ej1 = N (N (H "A") "B" (H "B")) "B" (N (H "C") "A" (H "C"))

Definir la función

enumeraArbol :: Arbol t -> Arbol Int

tal que (enumeraArbol a) es el árbol obtenido numerando las hojas y los nodos de a desde la hoja izquierda hasta la raíz. Por ejemplo,

λ> enumeraArbol ej1
N (N (H 0) 1 (H 2)) 3 (N (H 4) 5 (H 6))

Gráficamente,

      3
     / \
    /   \
   /     \
  1       5
 / \     / \
0   2   4   6

Actualización de «Biparticiones de una lista»

He actualizado las soluciones del ejercicio Biparticiones de una lista cuyo enunciado es


Definir la función

biparticiones :: [a] -> [([a],[a])]

tal que (biparticiones xs) es la lista de pares formados por un prefijo de xs y el resto de xs. Por ejemplo,

λ> biparticiones [3,2,5]
[([],[3,2,5]),([3],[2,5]),([3,2],[5]),([3,2,5],[])]
λ> biparticiones "Roma"
[("","Roma"),("R","oma"),("Ro","ma"),("Rom","a"),("Roma","")]

Actualización de «Mayor producto de las ramas de un árbol»

He actualizado las soluciones del ejercicio Mayor producto de las ramas de un árbol cuyo enunciado es


Los árboles se pueden representar mediante el siguiente tipo de datos

data Arbol a = N a [Arbol a]
  deriving Show

Por ejemplo, los árboles

  1              3
 / \            /|\
2   3          / | \
    |         5  4  7
    4         |     /\
              6    2  1

se representan por

ej1, ej2 :: Arbol Int
ej1 = N 1 [N 2 [],N 3 [N 4 []]]
ej2 = N 3 [N 5 [N 6 []], N 4 [], N 7 [N 2 [], N 1 []]]

Definir la función

mayorProducto :: (Ord a, Num a) => Arbol a -> a

tal que (mayorProducto a) es el mayor producto de las ramas del árbol a. Por ejemplo,

λ> mayorProducto (N 1 [N 2 [], N  3 []])
3
λ> mayorProducto (N 1 [N 8 [], N  4 [N 3 []]])
12
λ> mayorProducto (N 1 [N 2 [],N 3 [N 4 []]])
12
λ> mayorProducto (N 3 [N 5 [N 6 []], N 4 [], N 7 [N 2 [], N 1 []]])
90
λ> mayorProducto (N (-8) [N 0 [N (-9) []],N 6 []])
0
λ> a = N (-4) [N (-7) [],N 14 [N 19 []],N (-1) [N (-6) [],N 21 []],N (-4) []]
λ> mayorProducto a
84

Actualización de «Número de pares de elementos adyacentes iguales en una matriz»

He actualizado las soluciones del ejercicio Número de pares de elementos adyacentes iguales en una matriz cuyo enunciado es


Una matriz se puede representar mediante una lista de listas. Por ejemplo, la matriz

|2 1 5|
|4 3 7|

se puede representar mediante la lista

[[2,1,5],[4,3,7]]

Definir la función

numeroParesAdyacentesIguales :: Eq a => [[a]] -> Int

tal que (numeroParesAdyacentesIguales xss) es el número de pares de elementos consecutivos (en la misma fila o columna) iguales de la matriz xss. Por ejemplo,

numeroParesAdyacentesIguales [[0,1],[0,2]]              ==  1
numeroParesAdyacentesIguales [[0,0],[1,2]]              ==  1
numeroParesAdyacentesIguales [[0,1],[0,0]]              ==  2
numeroParesAdyacentesIguales [[1,2],[1,4],[4,4]]        ==  3
numeroParesAdyacentesIguales ["ab","aa"]                ==  2
numeroParesAdyacentesIguales [[0,0,0],[0,0,0],[0,0,0]]  ==  12
numeroParesAdyacentesIguales [[0,0,0],[0,1,0],[0,0,0]]  ==  8

Actualización de «Elemento más repetido de manera consecutiva»

He actualizado las soluciones del ejercicio Elemento más repetido de manera consecutiva cuyo enunciado es


Definir la función

masRepetido :: Ord a => [a] -> (a,Int)

tal que (masRepetido xs) es el elemento de xs que aparece más veces de manera consecutiva en la lista junto con el número de sus apariciones consecutivas; en caso de empate, se devuelve el mayor de dichos elementos. Por ejemplo,

masRepetido [1,1,4,4,1]  ==  (4,2)
masRepetido [4,4,1,1,5]  ==  (4,2)
masRepetido "aadda"      ==  ('d',2)
masRepetido "ddaab"      ==  ('d',2)
masRepetido (show (product [1..5*10^4]))  ==  ('0',12499)