-- 1ª solución
-- ===========
mayorCapicuaP1 :: Integer -> Integer
mayorCapicuaP1 n = head (capicuasP n)
-- (capicuasP n) es la lista de las capicúas de 2*n cifras que
-- pueden escribirse como productos de dos números de n cifras. Por
-- ejemplo, Por ejemplo,
-- ghci> capicuasP 2
-- [9009,8448,8118,8008,7227,7007,6776,6336,6006,5775,5445,5335,
-- 5225,5115,5005,4884,4774,4664,4554,4224,4004,3773,3663,3003,
-- 2992,2772,2552,2442,2332,2112,2002,1881,1771,1551,1221,1001]
capicuasP n = [x | x <- capicuas n,
not (null (productosDosNumerosCifras n x))]
-- (capicuas n) es la lista de las capicúas de 2*n cifras de mayor a
-- menor. Por ejemplo,
-- capicuas 1 == [99,88,77,66,55,44,33,22,11]
-- take 7 (capicuas 2) == [9999,9889,9779,9669,9559,9449,9339]
capicuas :: Integer -> [Integer]
capicuas n = [capicua x | x <- numerosCifras n]
-- (numerosCifras n) es la lista de los números de n cifras de mayor a
-- menor. Por ejemplo,
-- numerosCifras 1 == [9,8,7,6,5,4,3,2,1]
-- take 7 (numerosCifras 2) == [99,98,97,96,95,94,93]
-- take 7 (numerosCifras 3) == [999,998,997,996,995,994,993]
numerosCifras :: Integer -> [Integer]
numerosCifras n = [a,a-1..b]
where a = 10^n-1
b = 10^(n-1)
-- (capicua n) es la capicúa formada añadiendo el inverso de n a
-- continuación de n. Por ejemplo,
-- capicua 93 == 9339
capicua :: Integer -> Integer
capicua n = read (xs ++ (reverse xs))
where xs = show n
-- (productosDosNumerosCifras n x) es la lista de los números y de n
-- cifras tales que existe un z de n cifras y x es el producto de y por
-- z. Por ejemplo,
-- productosDosNumerosCifras 2 9009 == [99,91]
productosDosNumerosCifras n x = [y | y <- numeros,
mod x y == 0,
div x y `elem` numeros]
where numeros = numerosCifras n
-- 2ª solución
-- ===========
mayorCapicuaP2 :: Integer -> Integer
mayorCapicuaP2 n = maximum [x*y | x <- [a,a-1..b],
y <- [a,a-1..b],
esCapicua (x*y)]
where a = 10^n-1
b = 10^(n-1)
-- (esCapicua x) se verifica si x es capicúa. Por ejemplo,
-- esCapicua 353 == True
-- esCapicua 357 == False
esCapicua :: Integer -> Bool
esCapicua n = xs == reverse xs
where xs = show n
-- 3ª solución
-- ===========
mayorCapicuaP3 :: Integer -> Integer
mayorCapicuaP3 n = maximum [x*y | (x,y) <- pares a b,
esCapicua (x*y)]
where a = 10^n-1
b = 10^(n-1)
-- (pares a b) es la lista de los pares de números entre a y b de forma
-- que su suma es decreciente. Por ejemplo,
-- pares 9 7 == [(9,9),(8,9),(8,8),(7,9),(7,8),(7,7)]
pares a b = [(x,z-x) | z <- [a1,a1-1..b1],
x <- [a,a-1..b],
x <= z-x, z-x <= a]
where a1 = 2*a
b1 = 2*b
-- 4ª solución
-- ===========
mayorCapicuaP4 :: Integer -> Integer
mayorCapicuaP4 n = maximum [x | y <- [a..b],
z <- [y..b],
let x = y * z,
let s = show x,
s == reverse s]
where a = 10^(n-1)
b = 10^n-1
-- 5ª solución
-- ===========
mayorCapicuaP5 :: Integer -> Integer
mayorCapicuaP5 n = maximum [x*y | (x,y) <- pares2 b a, esCapicua (x*y)]
where a = 10^(n-1)
b = 10^n-1
-- (pares2 a b) es la lista de los pares de números entre a y b de forma
-- que su suma es decreciente. Por ejemplo,
-- pares2 9 7 == [(9,9),(8,9),(8,8),(7,9),(7,8),(7,7)]
pares2 a b = [(x,y) | x <- [a,a-1..b], y <- [a,a-1..x]]
-- 6ª solución
-- ===========
mayorCapicuaP6 :: Integer -> Integer
mayorCapicuaP6 n = maximum [x*y | x <- [a..b],
y <- [x..b] ,
esCapicua (x*y)]
where a = 10^(n-1)
b = 10^n-1
-- (cifras n) es la lista de las cifras de n en orden inverso. Por
-- ejemplo,
-- cifras 325 == [5,2,3]
cifras :: Integer -> [Integer]
cifras n
| n < 10 = [n]
| otherwise = (ultima n) : (cifras (quitarUltima n))
-- (ultima n) es la última cifra de n. Por ejemplo,
-- ultima 325 == 5
ultima :: Integer -> Integer
ultima n = n - (n `div` 10)*10
-- (quitarUltima n) es el número obtenido al quitarle a n su última
-- cifra. Por ejemplo,
-- quitarUltima 325 => 32
quitarUltima :: Integer -> Integer
quitarUltima n = (n - (ultima n)) `div` 10
-- 7ª solución
-- ===========
mayorCapicuaP7 :: Integer -> Integer
mayorCapicuaP7 n = head [x | x <- capicuas n, esFactorizable x n]
-- (esFactorizable x n) se verifica si x se puede escribir como producto
-- de dos números de n dígitos. Por ejemplo,
-- esFactorizable 1219 2 == True
-- esFactorizable 1217 2 == False
esFactorizable x n = aux i x
where b = 10^n-1
i = floor (sqrt (fromIntegral x))
aux i x | i > b = False
| x `mod` i == 0 = x `div` i < b
| otherwise = aux (i+1) x
-- Comparación de eficiencia
-- =========================
-- λ> mayorCapicuaP1 3
-- 906609
-- (0.07 secs, 18,248,224 bytes)
-- λ> mayorCapicuaP2 3
-- 906609
-- (0.51 secs, 555,695,720 bytes)
-- λ> mayorCapicuaP3 3
-- 906609
-- (0.96 secs, 780,794,768 bytes)
-- λ> mayorCapicuaP4 3
-- 906609
-- (0.24 secs, 255,445,448 bytes)
-- λ> mayorCapicuaP5 3
-- 906609
-- (0.33 secs, 317,304,080 bytes)
-- λ> mayorCapicuaP6 3
-- 906609
-- (0.26 secs, 274,987,472 bytes)
-- λ> mayorCapicuaP7 3
-- 906609
-- (0.02 secs, 1,807,720 bytes)
--
-- λ> mayorCapicuaP1 5
-- 9966006699
-- (9.90 secs, 6,349,454,544 bytes)
-- λ> mayorCapicuaP7 5
-- 9966006699
-- (0.06 secs, 15,958,616 bytes)